计算机体系结构 23:缓存一致性与所有权转移
计算机体系结构 23:缓存一致性与所有权转移
核心问题
第 16 到第 22 篇把单核视角里的 cache、DRAM、TLB、异常和数据布局串起来。多核一出现,同一个地址可能同时存在于多个核心的私有 cache 中。问题不再只是“这次访问命中哪一级”,而是:某个核心写了一个地址后,其他核心还能不能读到旧副本;某个 cache line 的最新值到底来自内存,还是来自另一个核心的脏副本。
缓存一致性解决的是单个地址的副本管理。它不保证所有地址上的操作都像单线程那样排成一个全局序列;跨地址顺序属于内存一致性模型,第 24 篇单独处理。本篇只回答一个可验收的问题:对一个 cache line,如何用失效、共享、独占和脏所有者转移,维持“同一时刻最多一个可写副本”和“读到的值来自最近一次有效写入”。
本文附件:
证据等级:功能执行。模型是 Python 标准库写成的单 cache line 教学状态机,复跑时会检查 SWMR 断言、失效确认、脏数据来源和最终内存值。它不是商品处理器 MESI 验证器。
边界
Sorin、Hill、Wood 的一致性教材把 cache coherence 的核心约束拆成两个不变量。第一是 SWMR,也就是 single-writer/multiple-reader:任一逻辑时间点,一个内存位置要么有一个可写副本,要么有多个只读副本。第二是 data-value invariant:读操作应该返回同一位置最近写入后允许被观察到的值。教材也明确区分 coherence 和 consistency:coherence 主要处理同一地址,consistency 决定不同地址上的操作如何排序。
本文模型只覆盖最小可检查子集:三个核心 C0/C1/C2,一个 cache line,状态取 I/S/E/M,请求按脚本顺序串行发生。模型记录每次读写后的各核心状态、各 cache 副本的值、内存值、失效确认列表和数据来源。没有 transient 状态、总线竞争、目录协议、NACK/retry、替换、DMA、I/O 设备一致性或真实互连延迟。
这个边界有意收窄。若先把 transient 和乱序消息加入模型,读者很容易把“协议工程细节”误认为“coherence 的基本判据”。本篇先固定单行串行模型,让每个状态转换都能用手算检查。
MESI 状态怎样承载所有权
四个状态的含义如下:
| 状态 | 含义 | 是否可直接读 | 是否可直接写 | 是否可能比内存新 |
|---|---|---|---|---|
| I | 无效副本 | 否 | 否 | 否 |
| S | 共享只读副本 | 是 | 否 | 否 |
| E | 独占干净副本 | 是 | 是 | 否 |
| M | 独占脏副本 | 是 | 是 | 是 |
E 和 M 都是“可写副本”,所以模型的 SWMR 断言把它们算作 writer-capable copy。若某个核心处于 M,其他核心不能同时处于 S/E/M。若多个核心处于 S,它们都只能读;其中任意一个要写,必须先发出取得所有权的请求,把其他共享副本失效。
一次写 miss 或共享副本升级写入,在模型中用 write_getm 表示。GetM 的关键不是“写一个新值”这一行代码,而是先完成所有其他有效副本的失效确认。脚本把被失效的核心列入 invalidation_acks。每个事件写入 trace 之前都会运行:
1 | |
这段断言只检查 SWMR,不检查消息协议是否完整。它能抓住最基本的错误:两个核心同时持有可写副本,或者一个核心可写时另一个核心还保留共享读副本。
核心轨迹
复现实验命令:
1 | |
本次输出:
1 | |
轨迹中的主要事件可以手算复核。
初始状态是三份 I,内存值为 0。C0 第一次读 miss,没有其他副本,直接从内存取值 0,并进入 E:
1 | |
C1 随后读同一行。C0 的 E 副本是干净独占副本,模型把 C0 降为 S,把 C1 也置为 S,两者都读 0:
1 | |
此时可以有多个读者,但没有写者。C0 写入 7 时必须取得独占写权限。它发出 GetM,使 C1 的共享副本失效,收到 C1 的失效确认后进入 M,本地值变成 7:
1 | |
这里内存仍然是 0,最新值只在 C0 的脏副本里。若后续 C1 读 miss,不能从内存直接读 0。模型查到 dirty owner 是 C0,把 7 从 C0 供应给 C1,同时把内存更新为 7,并让两者进入 S:
1 | |
随后 C2 写入 9,要失效 C0/C1 两个共享副本,进入 M。C0 再读时,数据来源是 C2 的脏副本,最终内存和值都到 9。
这个轨迹说明两个点。第一,写权限是所有权,不只是 cache 中有一份数据。第二,脏数据的来源可能是另一个 cache,而不是内存。若模型在 C1 读 miss 时直接读内存 0,SWMR 仍可能成立,但 data-value invariant 已经被破坏。
验收结果
mesi_summary.txt 记录:
1 | |
本文验收项对应为:
- 能解释
S/E/M/I各自代表的读写权限和内存新旧关系。 - 能在
C0=M(value 7)后说明C1读 miss 的数据来源必须是C0,不能是旧内存。 - 能检查每个事件后是否仍满足 SWMR。
- 能说明该模型没有覆盖 transient 状态、消息竞态、目录扩展性和真实硬件时延。
练习
练习 1
已知 C0=M(value 5),内存仍为 0,C1/C2=I。此时 C1 读同一 cache line。读到的值、数据来源、结束状态分别是什么?
答案线索:C0 是 dirty owner。C1 不能从内存读 0,而要从 C0 取得 5。结束后常见教学转换是 C0=S(value 5), C1=S(value 5), C2=I, memory=5。
练习 2
只检查 SWMR 是否足以证明读值正确?
答案线索:不够。例子是 C0=M(value 7), memory=0 后 C1 读 miss。如果协议错误地让 C1 从内存读 0,并把 C0/C1 都改成 S,SWMR 形式上可能没有两个写者,但读值已经违反 data-value invariant。






