news 2026/5/10 15:11:45

A Primer on Memory Consistency and Cache Coherence(内存一致性与缓存一致性入门)学习:第七章:监听式缓存一致性协议 —— 详细中文解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
A Primer on Memory Consistency and Cache Coherence(内存一致性与缓存一致性入门)学习:第七章:监听式缓存一致性协议 —— 详细中文解析

目录

  1. 监听协议的核心思想
  2. 为什么需要全局总序
  3. 基准监听协议:MSI
  4. 添加 Exclusive 状态:MESI
  5. 添加 Owned 状态:MOSI
  6. 非原子性总线与分离事务总线
  7. 总线互联网络的优化
  8. 真实商业系统案例
  9. 监听协议的现状与未来
  10. C++ 完整模拟代码

1. 监听协议的核心思想

1.1 什么是"监听"

监听协议(Snooping Protocol)的核心只有一句话:

所有缓存一致性控制器,以相同的顺序观察(监听)所有一致性请求,并各自独立地"做正确的事"来维护一致性。
类比生活场景:

想象一个教室里的广播系统: 老师(某个核心)说:「我要独占使用黑板!」 所有同学(其他核心)都听到了这句话(监听) 每个人各自决定:「好,我把手里的黑板照片作废掉」 关键:所有人听到的是同一句话,顺序也相同

传统监听协议通过有序广播网络(如共享总线)来传播请求,保证每个控制器观察到的请求序列完全一致,即存在一个全局总序(Total Order)

2. 为什么需要全局总序

2.1 有全局总序时的正确场景

下面用 ASCII 时序图展示:核心 C1 和 C2 都想以 M 状态获取同一个块 A。

时刻 C1 的视角 C2 的视角 LLC/内存的视角 ---- ---------- ---------- --------------- 0 A:I A:I A:I(内存是所有者) 1 A:GetM(C1) A:GetM(C1) A:GetM(C1) -> C1得到M -> A:M -> A:I -> 内存失去所有权 2 A:GetM(C2) A:GetM(C2) A:GetM(C2) -> C2得到M -> A:I -> A:M -> 内存仍无所有权

三者都看到同样的顺序:C1 的 GetM 在前,C2 的 GetM 在后,所以各自状态机推进一致,不会出现两个人同时处于 M 状态的情况。

2.2 没有全局总序时的错误场景

时刻 C1 的视角 C2 的视角 LLC/内存的视角 ---- ---------- ---------- --------------- 0 A:I A:I A:I 1 [C1先看到C1] [C2先看到C2] [先看到C1] A:GetM(C1) A:GetM(C2) A:GetM(C1) -> A:M -> A:M 结果:C1 和 C2 同时认为自己是 M 状态! 违反了 SWMR 不变式!

C1 和 C2 同时处于 M 状态意味着两个核心可以同时写同一个块,这是严重的一致性错误。

2.3 全局总序与内存一致性模型的关系

全局总序不仅保证一致性,还对内存一致性模型(SC、TSO)有影响。
考虑两个块 A 和 B 的场景,无全局总序时可能产生违反 SC/TSO 的执行:

C1 执行:store A=1,store B=1 C2 执行:r1=load B,r2=load A 期望(SC/TSO):如果 r1=1,那么 r2 也应该=1 实际(无总序):r1=1,r2=0 <-- 违反!

有了全局总序后:C2 在看到 B 的新值之前,必然先看到 A 的无效化请求,所以再次读 A 时只能得到新值,结果满足 SC/TSO。

2.4 序列化点(Serialization Point)

总线仲裁逻辑就是序列化点:

多个控制器同时发请求 | v [总线仲裁逻辑] <-- 序列化点:决定哪个请求先上总线 | 只有一个请求被允许上总线 | v 所有控制器都监听到这个请求

关键点:请求在序列化点被排序的那一刻,事务就逻辑上完成了,即使数据响应还没到达请求者。这与乱序执行处理器中"指令按程序序提交"的概念类似。

2.5 响应消息不需要总序

监听协议只要求请求消息有总序,响应消息(携带数据)则:

  • 不需要广播
  • 不需要有序
  • 可以走独立的、更廉价的网络
    这是一个重要的优化机会:数据消息体积大,如果走广播总线会浪费带宽;走单独网络可以大幅提升性能。

3. 基准监听协议:MSI

3.1 协议概述

MSI 协议只有三个稳定状态:

状态含义可读可写谁是所有者
M(Modified)已修改,独占本缓存
S(Shared)共享,只读LLC/内存
I(Invalid)无效

使用写回缓存(Write-Back Cache):写操作只写到本地缓存,驱逐时才写回内存。

3.2 简单系统模型:原子请求 + 原子事务

原子请求(Atomic Requests):请求发出的同一周期内就被排序,不可能有其他请求插进来。
原子事务(Atomic Transactions):一个事务(请求+响应)完全结束后,下一个针对同一块的请求才能出现在总线上。

原子总线示意(时间从左到右): 地址总线: [请求1] [请求2] [请求3] 数据总线: [响应1] [响应2] 特点:必须等响应1完成,请求2才能上总线 缺点:总线利用率低,等待时间长

3.3 MSI 状态转换图(缓存控制器)

Own-GetS

Own-GetM

Own-GetM

Other-GetM 或 静默替换

Other-GetS

Other-GetM 或 Own-PutM

I
无效

S
共享只读

M
已修改

3.4 MSI 状态转换图(内存控制器)

GetM

GetS 或 PutM

IorS
内存是所有者

M
某缓存是所有者

3.5 过渡状态说明

由于发出请求和收到响应之间存在时间差,需要过渡状态:

过渡状态含义
ISDI -> S,已收到自己的 GetS,等 Data
IMDI -> M,已收到自己的 GetM,等 Data
SMDS -> M,已收到自己的 GetM,等 Data
ISADI -> S,已发 GetS,等总线确认(非原子请求时)
IMADI -> M,已发 GetM,等总线确认
SMADS -> M,已发 GetM,等总线确认
MIAM -> I,已发 PutM,等总线确认
IIAI -> I(中间态),先把块给别人了,等自己的 PutM 被确认

3.6 运行示例(非原子请求 + 原子事务)

初始状态:C1=I,C2=I,LLC=IorS 周期 C1 C2 LLC 总线请求 总线数据 1 发GetS/ISAD 2 发GetM/IMAD 3 GetS(C1) 4 ->ISD 发Data给C1/IorS 5 Data(LLC->C1) 6 复制到缓存/S GetM(C2) 7 ->I ->IMD 发Data给C2/M 8 Data(LLC->C2) 9 复制/M 10 发GetS/ISAD 11 GetS(C1) 12 ->ISD 发数据给C1和LLC/S ->IorSD 13 Data(C2->C1) 14 复制/S 复制/IorS

3.7 S 状态的静默驱逐

S 状态的块被驱逐时,不需要发任何消息(静默驱逐),因为:

  • 其他缓存的行为不因此改变
  • LLC/内存仍然持有有效副本
    但 M 状态的块驱逐时,必须发 PutM 并把数据写回内存,因为 M 状态的缓存是唯一持有有效数据的地方。

4. 添加 Exclusive 状态:MESI

4.1 为什么要加 E 状态

考虑一个常见场景:

MSI 协议下: 核心读块 A --> 发 GetS --> 得到 S 状态 核心写块 A --> 发 GetM --> 得到 M 状态 共计:2 次事务,2 次总线占用 MESI 协议下(如果读时没有其他人持有该块): 核心读块 A --> 发 GetS --> 得到 E 状态(独占干净) 核心写块 A --> 静默升级 E -> M(无需总线通信!) 共计:1 次事务,节省了 50% 的总线带宽

E 状态的条件:
E 状态 ⇔ (只有我有这个块) ∧ (内存副本是最新的) \text{E 状态} \Leftrightarrow \text{(只有我有这个块)} \wedge \text{(内存副本是最新的)}E状态(只有我有这个块)(内存副本是最新的)

4.2 如何知道"只有我有"

有两种方案,MESI 协议采用方案二(保守 S 状态):
方案一:总线上添加一根"共享者信号线"(wired-OR),GetS 发出时其他持有 S 的缓存拉高信号线,请求者通过信号线判断是否有共享者。缺点:需要额外物理线路。
方案二(采用):LLC 保守地跟踪共享状态:

  • LLC 处于 I 状态 => 肯定没有其他缓存持有 => 响应时标记为"独占数据"
  • LLC 处于 S 状态 => 可能有其他缓存持有(保守估计) => 响应普通数据
    "保守"的意思是:即使最后一个 S 副本被静默驱逐,LLC 也不会立即知道,它会继续保持 S 状态一段时间,错过一些可以给 E 的机会,但这没有正确性问题。

4.3 MESI 状态转换图(缓存控制器)

Own-GetS 且 LLC在I态

Own-GetS 且 LLC不在I态

Own-GetM

Own-GetM

Other-GetM 或 静默替换

静默升级

Other-GetS

Other-GetM 或 Own-PutM

Other-GetS

Other-GetM 或 Own-PutM

I
无效

S
共享只读

E
独占干净

M
已修改

4.4 MESI 状态转换图(内存控制器)

GetS

GetM

GetS 或 GetM

GetS 或 PutM

GetM

I
无共享者

S
有共享者

EorM
某缓存独占或已修改

4.5 MESI 运行示例

初始状态:C1=I,C2=I,LLC=I(注意:LLC 是 I 而不是 IorS) 周期 C1 C2 LLC 总线 1 发GetS/ISAD 2 发GetM/IMAD 3 GetS(C1) 4 ->ISD 发独占Data给C1/EorM 5 独占Data(LLC->C1) 6 复制/E(独占!) GetM(C2) 7 S ->IMD ->MD 8 Data(C1->C2) 9 复制/M 10 发GetS/ISAD 11 GetS(C1) 12 ->ISD 发Data给C1和LLC/S ->SD 13 Data(C2->C1) 14 复制/S 复制/S 对比MSI:步骤6时C1得到E而不是S,步骤7时C2的GetM 不需要等内存响应,直接从C1的缓存获得数据。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 15:10:10

3分钟掌握VideoDownloadHelper:你的浏览器视频下载神器

3分钟掌握VideoDownloadHelper&#xff1a;你的浏览器视频下载神器 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 还在为无法保存网页视频而…

作者头像 李华
网站建设 2026/5/10 15:09:05

C++ append()函数实战:从基础语法到高效字符串拼接场景

1. 为什么append()是C字符串处理的核心武器 第一次用C处理字符串拼接时&#xff0c;我像大多数新手一样习惯性地用操作符。直到某天调试一个网络服务时&#xff0c;发现日志模块的性能瓶颈竟然出现在简单的字符串拼接上——这就是我与append()函数的初次相遇。这个看似普通的成…

作者头像 李华
网站建设 2026/5/10 15:08:17

从传感器噪声到平滑曲线:一个物联网工程师的Python数据滤波实战笔记(附Arduino数据样例)

从传感器噪声到平滑曲线&#xff1a;一个物联网工程师的Python数据滤波实战笔记 当ESP32微控制器通过I2C总线传回温度传感器读数时&#xff0c;屏幕上跳动的数字总让人心生疑虑——究竟是环境真实波动&#xff0c;还是传感器自身的噪声在作祟&#xff1f;这个问题困扰着每一位需…

作者头像 李华
网站建设 2026/5/10 15:08:10

大模型推理延迟飙升83%?奇点智能大会闭门报告首次公开:4层熔断+2级降级+1套SLA量化治理体系(附开源治理SDK)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;大模型服务治理&#xff1a;奇点智能大会 在2024年奇点智能大会上&#xff0c;大模型服务治理成为核心议题。随着LLM推理服务规模化部署&#xff0c;企业面临模型版本混乱、流量调度失衡、SLA保障缺失等…

作者头像 李华
网站建设 2026/5/10 15:06:15

PostgreSQL密码安全实操:除了ALTER USER,你的修改方式可能正在泄露密码

PostgreSQL密码安全深度实践&#xff1a;从风险规避到体系化防护 在数据库管理领域&#xff0c;密码安全往往被视为基础却容易被忽视的一环。许多开发者认为修改密码只需执行一条简单的ALTER USER语句&#xff0c;却不知道这种常规操作可能正在将敏感凭证暴露在多个日志系统中。…

作者头像 李华