CPU缓存一致性协议MESI 的理解
关于CPU缓存一致性协议MESI,已经有很多文章详细的介绍,如下
https://www.cnblogs.com/yanlong300/p/8986041.html
以下是我个人对这个协议的理解。
首先,CPU与缓存及内存及总线的关系如下图所示:
所以CPU获取数据是直接从缓存中获取,不是从内存中获取。
由于现在CPU架构支持多核,所以多核CPU的情况下有多个一级缓存,如何保证多个CPU的多个缓存内部数据的一致,不让系统数据混乱。这里就引出了一个一致性的协议MESI。
分析前,有以下几个前提:
1.CPU获取数据是直接从缓存中获取,不是从内存中获取。
2.CPU读取缓存数据的基本单位是缓存行。
3.CPU读取缓存行,并不是直接获取,要根据缓存行的状态(MESI)来判断当前缓存行的数据使用有效,再进行读取。
4.CPU写缓存行时,只能有一个CPU进行写。
通过两种场景分析缓存一致性协议MESI。
场景一:CPU读数据(静态情况)
如果缓存行的状态为“I”,则代表数据无效需要从内存中获取数据,更新到缓存行中,然后状态变为“S”。
如果缓存行的状态为“MES”(不是“I”),则直接从缓存行中获取数据。
总结:读数据时,缓存行就是两个状态“I”和非“I”,只要是非“I”就从缓存行中直接读取数据,否则从内存中读取数据。
那非“I”中,为什么又有三种状态呢?主要是应用在一个CPU写数据,及其他CPU缓存行数据的变化
场景二:CPU写数据到缓存行(动态情况)
如果一个CPU打算写数据到缓存行,
1.首先发消息到BUS,通知其他CPU缓存行,其数据无效,更新其状态为“I”,
2.然后将本缓存行状态变为“E”表示独占该缓存行,
3.然后修改缓存行信息,将本缓存行状态变为“M”表示修改该缓存行,
4.监听BUS消息,如果有其他CPU获取其缓存行数据,需要在其他CPU从内存获取前将数据刷新到内存中,
5.刷新缓存行到内存后,更新本缓存行的状态为“S”(稳定态)。
CAS基于MESI的应用
取自以下的1.3节,进行了部分删减及修改
https://www.jianshu.com/p/6745203ae1fe
在x86架构上,当两个core同时执行针对同一地址的CAS指令时,其实他们是在试图修改每个core自己持有的Cache line,
假设两个core都持有相同地址对应cacheline,且各自cacheline 状态为S, 这时如果要想成功修改,就首先需要把S转为E, 则需要向其它core invalidate 这个地址的cacheline,则两个core都会向ring bus发出 invalidate这个操作, 那么在ringbus上就会根据特定的设计协议仲裁是core0,还是core1能赢得这个invalidate, 胜者完成操作, 失败者需要接受结果, invalidate自己对应的cacheline,再读取胜者修改后的值, 回到起点.
对于我们的CAS操作来说, 其实锁并没有消失,只是转嫁到了ring bus的总线仲裁协议中. 而且大量的多核同时针对一个地址的CAS操作会引起反复的互相invalidate 同一cacheline, 造成pingpong效应, 同样会降低性能。当然如果真的有性能问题,我觉得这可能会在ns级别体现了,一般的应用程序中使用CAS应该不会引起性能问题