多核共享内存靠什么保证缓存一致?
更新时间:2026-09-21。问题驱动短答页。一致性协议见 Cache 一致性 MESI,Cache 组织见 Cache 组织与替换,SoC 一致性总线见 CHI/ACE 一致性总线。
一句话回答
每个核心都有自己的 cache 时,同一内存地址会在多个 cache 里有副本;一个核写了新值,别的核若还抱着旧副本就会读到过期数据。硬件缓存一致性协议(最典型的是 MESI)给每个 cache 行打上状态,并通过总线嗅探(广播「我要写了,你们作废副本」)或目录(集中记录谁持有副本)自动让所有 cache 收敛到同一视图,对软件呈现「单一内存」的假象,普通 load/store 不用手动刷 cache。
MESI 四态
每个 cache 行处于四态之一:
| 状态 | 含义 |
|---|---|
| M(Modified) | 本 cache 已修改、与内存不一致,只有我有,我负责写回 |
| E(Exclusive) | 与内存一致且只有我有副本 |
| S(Shared) | 与内存一致且可能多个核都有副本(只读) |
| I(Invalid) | 无效,读它要重新取 |
核 0 要写某行时,协议先发独占/失效请求,把其他核里该行统统打成 I,自己拿到 M 才能写;其他核下次读就会 miss 并取到新值。这样「谁改了、谁还有副本、该谁写回」都有明确规则。
嗅探 vs 目录
- 总线嗅探(snooping):所有一致性事务广播到总线上,每个 cache「嗅探」并检查自己有没有该行、要不要作废/提供数据。延迟低、实现直接,适合核心数不多;缺点是广播流量随核数上升,见 CHI/ACE。
- 目录(directory):用一个集中/分布式目录记录每个内存块当前被哪些核缓存、处于什么态,失效只发给真正持有副本的核,可扩展到几十上百核和多路/NUMA 系统,代价是目录存储和查询延迟。
一致性 ≠ 内存模型(重要)
- cache coherence(本节):硬件保证「同一地址」在各 cache 的值最终/按规则一致,针对的是数据新鲜度。
- 内存一致性模型 / 内存屏障:解决「不同地址」读写的可见顺序(如 store-store、store-load 能否重排),这要靠架构内存模型和 fence/屏障,不是 MESI 管的,见 写缓冲与内存屏障。软件里「改了 flag 对方没看到」往往是顺序问题,得加屏障而非刷 cache。
常见坑
- 把「一致性已保证」当成「不用同步」:一致性不提供原子性和顺序,多核并发写仍要锁/原子指令,见 硬件信号量/自旋锁。
- 软硬件维护混淆:MMIO/外设/DMA 缓冲区(不经过一致性域)才需要 clean/invalidate,普通内存不要乱刷,见 DMA 与 cache。
- 多核系统里某个 master 挂在一致性总线之外,却访问共享内存,产生不可见的旧数据。
- 误以为 MESI 消除了 false sharing:不同变量共享同一 cache 行仍会互相作废、性能下降。
总结
多核各自带 cache 会让同一地址存在多个副本,硬件通过一致性协议维护单一内存视图:MESI 用 M/E/S/I 四态规定每个 cache 行的所有权与写回责任,写前先把其他副本作废;小规模系统靠总线嗅探广播失效、大规模系统靠目录只通知持有者。要注意 cache 一致性保证的是同一地址的数据新鲜、对普通 load/store 透明,而不同地址访问的可见顺序属于内存模型、仍需内存屏障,并发原子性也仍要锁——一致性不等于不需要同步。