写在前面:该协议主要是为了解决Cache不一致问题而设计的,因为多核CPU的产生导致各个处理器内部的数据可能因为没有及时同步而产生一系列问题
MESI协议
为了保证Cache的一致性,CPU提供了两个操作:
-
Write invalidate:当某个内核修改了一份数据后,其它的内核如果同时也有这份数据的复制,那么就把这些未修改的数据置为无效
-
Write update:当某个内核修改了一份数据后,其它的内核如果同时也有这份数据的复制,那么就把这些未修改的数据及时同步更新
两种操作各有不同的适用场景,例如当上图中的Core 1和Core 2不再使用变量x的数据时,直接把它们invalidate是最方便的;若仍需要使用变量x的数据时,那么及时update是最好的选择
Cache一致性协议
上面提到的两个操作是最简单的思路,现今CPU上都采取了更高级的一致性协议。其中以奔腾处理器使用的MESI协议最为经典。在MESI协议中,每个Cache line有4个状态,分别是:
需要注意的是,M和E状态的Cache line是数据独有的,但是M状态下的数据是不一致的,而E状态下的数据是一致的。同时,S状态下只有一致的数据才能被多个Cache所共享,下面举例说明各个状态:
M状态和I状态
在Core 0修改了变量x的值后(由原来的3更改值为5),此时该Cache line变成了M状态,其它Core对应的Cache line应该变成I状态(之后再考虑是同步更新数据还是直接废弃)
E状态(独占)
当只有Core 0访问内存中的变量x时,此时Cache line更改为E状态,因为这个时候内核数据与内存数据是保持一致的
S状态(共享)
3个Core都访问内存获取变量x的数据,这个时候他们是共享的状态(不能一个访问内存,其它内核间直接复制?)
Cache line的状态迁移
在MESI协议中,每个Cache的控制器不仅知道自己的读写操作,同时也监听其它Cache的读写操作(及时保持数据的一致性),所以在MESI协议中每条Cache line存在着状态迁移,示意图如下:
MESI各个状态之间的迁移过程如下:
补充:
- Cache line除I状态外都可以响应CPU读数据的请求,处于I状态下的Cache line必须从内存中读取数据(变成S状态或E状态)才能满足CPU的读请求
- 一个写请求只有在该Cache line处于M或E状态下才能被执行,当处于S状态下时,必须先将其它缓存中的同一条Cache line变成I状态(也就是说不允许通过对其它Cache中的该条数据进行更变造成更改后的数据不一致情况,同一时间一条Cache line只能更改一次)
- Cache可以随时将一个非M状态的Cache line变成I状态,一个M状态的Cache line则必须先写回内存(保证数据正确性)
- 一个处于M状态的Cache line必须时刻监听所有试图读该Cache line相对就主存的操作,这种操作必须在缓存将该Cache line写回主存并将状态变成S状态之前被延迟执行。
- 一个处于S状态的Cache line也必须监听其它缓存使该Cache line无效或者独享该缓存行的请求,并将该Cache line变成I状态
参考
- 万木杨:《大话处理器》P160-163
- KeepGoing:【并发编程】MESI——CPU缓存一致协议
- ZoeyyoeZ:计算机体系结构(第五版)-复习-MESI&MOESI协议