缓存一致性协议:MESI
缓存一致性问题
在多处理器系统中,每个处理器都有自己的高速缓存,而它们又共享同一主内存 (MainMemory)。基于高速缓存的存储交互很好地解决了处理器与内存的速度矛盾,但是 也引入了新的问题:缓存一致性(CacheCoherence)。当多个处理器的运算任务都涉及同一 块主内存区域时,将可能导致各自的缓存数据不一致的情况,如果真的发生这种情况,那同步回到主内存时以谁的缓存数据为准呢?为了解决一致性的问题,需要各个处理器访问缓存时都遵循一些协议,在读写时要根据协议来进行操作,这类协议有MSI、MESI(IllinoisProtocol)、MOSI、Synapse、Firefly及DragonProtocol,等等。其结构如下:
缓存一致性协议四种状态
状态 | 描述 | 监听任务 |
---|---|---|
M 修改 (Modified) | 该Cache line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。 | 缓存行必须时刻监听所有试图读该缓存行相对就主存 |
E 独享、互斥 (Exclusive) | 该Cache line有效,数据和内存中的数据一致,数据只存在于本Cache中。 | 缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S(共享)状态。 |
S 共享 (Shared) | 该Cache line有效,数据和内存中的数据一致,数据存在于很多Cache中。 | 缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。 |
I 无效 (Invalid) | 该Cache line无效。 | 无 |
缓存一致性协议(MESI)流程
上面我们罗列了缓存一致性协议的四种状态,接下用一个流程来梳理一下四个状态的转换过程,看下图:
- 步骤一:处理器A读取了主内存中的缓存块a,并且写入了自己的缓存区中。并将该缓存块a(cpu中的缓存)修改转改为Exclusive(独享状态)。
- 步骤二:处理器B这个时候也读取了主内存中的缓存块a,它发现了a的状态为Exclusive,于是将a的状态改为了Share(共享状态),处理器A中的该状态行也监听到了这一行为,并将状态修改为了Share。
- 步骤三:处理器A这个时候需要修改a,发现它的状态为Share,于是将它的状态修改为了Modified,并广播提示其他cpu中该缓存行的状态从Share改成Invalid,于是其他CPU缓存区中a的状态都变成了Invalid(无效状态)。
- 步骤四:处理器B这个时候需要去读取a,发现了a的状态为Invalid,是无效的,那它就去主内存中去再次读取a。这一请求被处理器A中的Modified状态a监听到了,于是它先让处理器B的这次读取延迟,直到处理器A将自身缓存区中a的值写回主存中,并且将a的状态修改为Share之后,执行。这个时候处理器B也就很成功的从主内存中读取到了a,并且a的状态为Share(共享状态)
缓存一致性协议失效
那么什么情况下缓存行会失效呢?
- cpu不支持缓存一致性协议。
- 缓存数据大小超过缓存行大小。
在这两种情况下,使用总线加锁。
总线风暴问题
缓存一致性协议的信息是通过总线进行广播的,很明显缓存一致性协议最大的问题就是可能引起一致性流量风暴。之前我们看到总线在同一时刻仅仅只能被一个处理器使用。当有大量缓存被改动时候,或者同一个缓存块一直被改动时,会产生大量的缓存一致性流量。从而占用了总线。影响了其他正常的读写请求。