计算机组成与体系结构:Snooping-Based Protocols(监听式协议)
目录
什么是监听式协议?
Snooping 的总线模型
两种写策略:Write Update vs. Write Invalidate
1️⃣ Write-Invalidate(写失效)
2️⃣ Write-Update(写更新)
🔍 操作流程分析
🔷 P₁ 想要访问 A(读操作)
🔷 P₃ 想要访问 A(读操作)
🔷 P₁ 执行 A = A + 1(即写操作)
🔷 P₃ 想执行 A = A - 1(即对变量 A 进行写操作)
Coherence Miss(一致性未命中)
正确动作是什么?
什么是监听式协议?
Snooping 协议是多核处理器系统中用于维护缓存一致性的协议之一,特点是每个缓存控制器通过监听总线上的操作来判断是否需要更新或失效其本地缓存副本。
核心思想:
-
每个处理器的缓存控制器“监听”(snoop)其他处理器在总线上的数据请求(读/写)
-
缓存间通过广播通信来感知和维护共享数据的一致性
Snooping 的总线模型
-
所有核心共享一个 系统总线(Bus)
-
当某个核心发起读取或写入共享数据的请求,这个操作会被“广播”到总线
-
其他核心的缓存控制器通过监听这条总线来判断:自己是否缓存了这份数据,如果有,是否需要更新或作废(invalidate)
两种写策略:Write Update vs. Write Invalidate
这是 Snooping 协议中 处理“写操作”的两种基本策略:
1️⃣ Write-Invalidate(写失效)
原理:
当一个核心写某数据时,它通知所有其他缓存使该数据副本无效(Invalid),确保只有写入核心拥有有效副本。
操作流程:
-
核心 A 想修改地址 X,发现该地址也存在于 B 的 cache 中。
-
A 向总线广播“Invalidate X”消息。
-
所有其他 Cache 收到后,把该块标为无效(Invalid)。
-
A 再进行写操作,自己独占该数据。
优点:
-
避免了写操作广播数据,提高了总线带宽效率。
-
写操作后,只有一个副本,简化一致性维护。
缺点:
-
如果其他核心之后还要访问这个地址,会导致 频繁失效与重新加载(cache thrashing)。
常与 Write-back cache 配合使用。
2️⃣ Write-Update(写更新)
原理:
当一个核心写某数据时,它将新值广播给所有其他缓存,让他们更新副本。
操作流程:
-
核心 A 写地址 X,广播“Update X with value V”。
-
所有包含地址 X 的 cache 会立即更新它们的副本为新值 V。
优点:
-
保持所有 Cache 对数据的一致视图,无需失效。
-
在多个核心频繁读写同一地址时命中率更高。
缺点:
-
每次写操作都要广播更新,带宽消耗大。
-
不适合写操作密集的场景。
常与 Write-through cache 配合使用。
🔍 操作流程分析
条件背景
-
有四个处理器核心:P₁、P₂、P₃、P₄
-
每个处理器有自己的私有缓存
-
主存中变量 A = 7
-
所有处理器的缓存中初始都是空的
-
系统采用监听式一致性协议
-
所有处理器都监听一条共享总线(Bus)
🔷 P₁ 想要访问 A(读操作)
-
P₁ 本地访问 A → 缓存 Compulsory Miss
-
P₁ 向总线发送 BusRd(读取请求)
-
所有其他核心(P₂、P₃、P₄)监听总线,发现自己没有 A,不响应
-
主存响应请求,返回 A = 7
-
P₁ 将 A = 7 缓存入私有缓存
-
将状态设为 S(Shared)
🔷 P₃ 想要访问 A(读操作)
-
P₃ 本地访问 A → 缓存 Miss
-
P₃ 向总线发送 BusRd
-
所有其他核心监听请求
-
P₁ 发现自己缓存中有 A(状态 S),响应请求
-
数据通过总线传给 P₃(或由主存再次提供)
-
P₃ 缓存 A = 7
-
状态设置为 S(Shared)
-
P₁ 保持状态为 S(Shared)
🔷 P₁ 执行 A = A + 1(即写操作)
-
P₁ 准备对 A 写入,当前状态为 S
-
根据 MSI 协议,S 状态不能直接写,需要升级为 M(Modified)
-
P₁ 向总线广播 写意图请求(BusRdX)
表示:我要写 A,请其他核心放弃所有 A 的副本 -
所有其他核心监听总线
-
P₃ 检测到自己也缓存了 A,状态为 S
-
因为接收到写失效请求 → P₃ 将自己的缓存状态设为 I(Invalid)
-
-
总线确认其他副本都已失效 → P₁ 获得 A 的独占写权限
-
P₁ 在缓存中将 A 从 7 改为 8
Write Through:
-
第 6 步中,P₁ 写入缓存 A = 8
-
同时将 A = 8 写回主存
-
主存更新为 8
Write Back:
-
第 6 步中,P₁ 写入缓存 A = 8
-
主存暂时不更新,仍保持 A = 7
-
P₁ 的缓存块标记为 “dirty(脏块)”
-
只有当:
-
P₁ 后续需要替换这个块,或
-
有其他处理器请求该地址时
-
才会触发将 A = 8 写回主存
-
🔷 P₃ 想执行 A = A - 1
(即对变量 A 进行写操作)
-
P₃ 想对 A 进行写操作
-
然而 P₃ 的缓存中,A 当前状态是 Invalid
-
Invalid 状态下,处理器不能对该数据进行读或写操作
因此:此时这不是一次有效写操作,而是一次 Cache Miss
我们现在遇到的不是一般的“缓存未命中”,而是专门属于缓存一致性协议中的一种特殊 Miss,称为:
Coherence Miss(一致性未命中)
当缓存中曾经拥有某个数据块的副本,但因为其他处理器修改了该数据而使本地副本失效(变为 Invalid),此时重新访问该数据发生的未命中。
-
P₃ 原本拥有变量 A 的副本,状态为 S
-
后来 P₁ 执行 A = A + 1
-
发送 BusRdX(写请求)
-
使 P₃ 的 A 副本失效 → 状态变为 I
-
-
现在 P₃ 再次访问 A,想写 A = A - 1
-
由于 P₃ 缓存中 A 是无效的,访问失败 → 这就是 Coherence Miss
正确动作是什么?
P₃ 不能直接写,它必须:
-
先触发 BusRdX(总线读-排他请求)
-
等待:
-
P₁ 将缓存中 A = 8 写回主存
-
P₁ 的状态变为 Invalid
-
-
然后从主存加载最新的 A = 8
-
放入 P₃ 的缓存,设置为 Modified
-
才能执行 A = A - 1,变为 7
📌 在 P₃ 发出 BusRdX 之前,A - 1
不能执行,系统会阻塞该指令