基于失效的缓存一致性协议 (invalid-based)
状态
MESI对应4种状态
已修改Modified(M)
缓存行是脏的 ,与主存值不同。如果别的CPU内核要读主存这块数据,该缓存行必须回写到主存,状态变为共享(S)
独占Exclusive(E)
缓存行只在当前缓存中,但是干净的(clean),与主存中数据一致。当别的缓存读取它时,状态变为共享;当前写数据时,变为已修改状态。
共享Shared(S)
缓存行也存在于其它缓存中且是干净的。缓存行可以在任意时刻抛弃。
无效Inivalid(I)
缓存行是无效的
操作
状态转换的两种场景:
- 缓存所在处理器的读写 & 其他处理器的读写
- 总线请求被总线窥探器监视
处理器对缓存的请求:
- PrRd: 处理器请求读一个缓存块
- PrWr: 处理器请求写一个缓存块
总线对缓存的请求:
- BusRd: 窥探器请求指出其他处理器请求读一个缓存块
- BusRdX: 窥探器请求指出其他处理器请求写一个该处理器不拥有的缓存块
- BusUpgr: 窥探器请求指出其他处理器请求写一个该处理器拥有的缓存块
- Flush: 窥探器请求指出请求回写整个缓存到主存
- FlushOpt: 窥探器请求指出整个缓存块被发到总线以发送给另外一个处理器(缓存到缓存的复制)
处理器操作带来的状态变化:
Invalid:
PrRead:
1.给总线发busRd信号 -> 其他处理器看到busRd,检查是否有有效的数据副本并通知发出请求的缓存,
如果有有效的副本,如果状态为M,需要先回写进内存,然后本地cache再从内存中读取数据,状态转为(S)Shared。
如果状态为S或E,则本地cache从内存中读取数据,并将这些缓存状态置为S
如果其他缓存都没有有效的副本,从内存中读取,本地缓存状态转为(E)Exclusive
PrWr:
给总线发BusRdx信号,转改转换为Modified。 如果其他缓存有有效副本,其中一个缓存发出数据,否则从主存中获得数据
如果其他缓存中有有效副本,见到busRdx信号后,本地缓存置为无效Invalid
MESI协议操作图解[5]
假定下述读/写操作访问同一主存位置的数据。操作流是 : R1, W1, R3, W3, R1, R3, R2. 最初所有缓存为空。 	
本地 请求 | P1 | P2 | P3 | 产生的 总线请求 | 数据提供者 | |
---|---|---|---|---|---|---|
0 | 最初 | - | - | - | - | - |
1 | R1 | E | - | - | BusRd | Mem |
2 | W1 | M | - | - | - | - |
3 | R3 | S | - | S | BusRd | P1's Cache |
4 | W3 | I | - | M | BusUpgr | - |
5 | R1 | S | - | S | BusRd | P3's Cache |
6 | R3 | S | - | S | - | - |
7 | R2 | S | S | S | BusRd | P1/P3's Cache |
总结
当cup去写数据时(M),如果操作的是共享变量(S),会发出信号通知其他cpu将该变量的缓存置为无效状态(I)。
因此当其他cpu需要读取这个变量时,发现自己缓存中该变量的缓存行是无效的,就会从内存中重新读取,确保一致性。
当读取数据时,其他cpu缓存行如果修改了数据,要先把数据写回主内存中
当修改数据时,其他cpu中该缓存行状态都必须失效
MESI 与内存屏障
MESI 如果简单粗暴地实现,会有两个很明显的性能问题:
- 当尝试写入一个 Invalid 缓存行时,需要等待从其它处理器或主存中读取最新数据,有较长的延时
- 将 cache line 置为 Invalid 状态也很慢
因此 CPU 在实现时一般会通过 Store Buffer 和 Invalidate Queue 机制来做优化