既然有MESI缓存一致性协议,为何还需volatile?

MESI缓存一致性协议

现在CPU都是多核cpu,且拥有多级缓存,如下图的CPU缓存模型

目前的CPU都是多核心的,每个核心都有自己的L1、L2缓存,当多个CPU同时操作同一份数据,就会出现缓存不一致的问题。

有两种解决方法:

  • 总线锁定
  • 缓存一致性协议(总线嗅探机制)

第一种的话,如果cpu某核要做i++操作,会向总线上发出一个LOCK#信号,阻塞了其他cpu,锁定期间开销较大,所以一般不采用这种方法。
此时,MESI缓存一致性协议应运而生,分为四种状态
各种状态含义如下:
M:被修改的。处于这一状态的数据,只在本CPU中有缓存数据,而其他CPU中没有。同时其状态相对于内存中的值来说,是已经被修改的,且没有更新到内存中。
E:独占的。处于这一状态的数据,只有在本CPU中有缓存,且其数据没有修改,即与内存中一致。
S:共享的。处于这一状态的数据在多个CPU中都有缓存,且与内存一致。
I:无效的。本CPU中的这份缓存已经无效。
值得注意的是,TSO内存模型后来引入了storebuffer,变成如下

因为MESI缓存一致性协议,所以L1,L2,L3等CPU多级缓存被抽象成cache,那么为什么要加入storebuffer
原因:

  • 如cpuA核要修改本地缓存,那么就需要将invalid状态发送给其他拥有该缓存数据的CPU缓存中,这过程会阻塞处理器,而storebuffer的出现,可以让处理器做其他事情,不会阻塞,等到收到所有的应答,才把storebuffer的数据更新到主存中。
    使用storebuffer有风险,因为不能保证数据何时保存,而storebuffer中如果有值,处理器会优先读取sb中的值。

从上面可以看出,MESI缓存一致性协议其实是保证了抽象cache的缓存一致性,而java中的volatile其实是通过内存屏障保证处理器到sb到L1缓存中间的防止指令的重排序导致不确定结果。
同时,volatile是java语言层面给出的保证,MESI缓存一致性协议只适用于L1/L2/L3 cache中,在storebuffer等影响下,仍然有重排序产生.

分析得比较浅显,本文仅仅是为自己复习起到抛砖引玉的作用。

posted @ 2020-11-21 00:03  计算机开冲  阅读(585)  评论(3编辑  收藏  举报