跳转至

写缓冲器和无效队列如何优化 MESI?

一、MESI 的性能问题

MESI 协议要求写操作时: 1. 广播无效化请求。 2. 等其他核确认。 3. 才能写。

这非常慢——CPU 写一个变量要等其他核回应。

二、写缓冲器(Store Buffer)

CPU 不等其他核回应,先把写操作放到写缓冲器里,继续执行后续指令。

核 A:
  写 x = 1 → 放进写缓冲器
  继续执行下一条指令(不等)
  ...
  稍后,写缓冲器的内容异步刷到缓存/内存

好处

写操作不阻塞 CPU。

问题

  • 写缓冲器是核私有的,其他核看不到。
  • 如果后续指令要读 x,得从写缓冲器里找(store forwarding)。
  • 多线程下,其他核看到的 x 可能是旧值。

三、无效化队列(Invalidate Queue)

核 A 收到其他核的无效化请求,不立即处理,先放到无效化队列里。

核 B 发无效化请求给核 A
核 A: 收到请求 → 放进无效化队列 → 立即回复"已收到"
核 A: 稍后才真正把缓存行标记为 Invalid

好处

核 B 不用等核 A 真正处理完就能继续写。

问题

核 A 回复了"已收到",但缓存行还没真正失效,核 A 可能还在读旧值。

四、内存屏障解决

  • StoreLoad:等写缓冲器排空,保证写对其他核可见。
  • LoadLoad:让无效化队列里的请求生效,保证读到最新值。

volatile 和 synchronized 的内存屏障就是干这个的。

五、总结

MESI 保证一致性,但慢
写缓冲器:写不等
无效化队列:收不等
快了,但出现可见性和有序性问题
内存屏障:显式等待
volatile / synchronized

理解

所有并发问题,本质都是"硬件为了快,偷偷优化了"。JMM 的 volatile、synchronized 就是告诉硬件"这里别优化"。