0%

高速缓存一致性

一、高速缓存一致性

在多CPU/CPU核环境中,存在不同CPU/CPU核内高速缓存数据不一致问题,为解决该问题,引入高速缓存一致性协议,MESI协议是众多高速缓存一致性协议中应用较为广泛的一种,接下来就基于MESI协议进行叙述,需要注意的是,MESI协议的不同具体实现可能是存在差异的。

在MESI协议中,同一主存数据块在不同CPU/CPU核内高速缓存上对应的Cache Line的状态修改是互相联动的,这免不了引入同步等待阻塞过程,降低了性能,比如“同一主存数据块在CPU/CPU核aC,bC,cC内高速缓存上对应的Cache Line分别为aA,bA,cA,状态都为S”场景:

  • aC修改aA,发送RW操作信号(失效信号)到内存总线,bC和cC收到该RW操作信号,将bA和cA的状态置为I,并发送ACK信号到内存总线,aC在收到bC和cC的两个ACK信号后,才继续将aA的状态置为M,否则同步等待阻塞

针对上述问题,引入“写缓冲器”和“失效队列”,化同步为异步,优化性能。针对上述场景,现在的过程如下:

  • aC修改aA,并不直接修改aA,而是将修改存入“写缓冲器”,发送RW操作信号(失效信号)到内存总线,此时aC完成该修改操作,继续做其他事情。bC和cC收到该RW操作信号,并不直接将bA和cA的状态置为I,而是将该失效信号存入“失效队列”,并在存入“失效队列”成功后发送ACK信号到内存总线(异步地从“失效队列”取出失效信号,将对应的Cache Line状态置为I),aC在收到bC和cC的两个ACK信号后,才取出“写缓冲器”的修改写入aA,并将aA的状态置为M

上述高速缓存-写缓冲器-失效队列+MESI协议机制,仍然会导致“狭义可见性”问题:

  • 在原始纯粹的多CPU/CPU核(内部包含“高速缓存”)机制中,存在“狭义可见性”问题
  • 在引入MESI协议后,由于不能实时保持同步,故不能避免“狭义可见性”问题
  • 在引入“写缓冲器”和“失效队列”机制后,他们会额外造成“狭义可见性”问题。比如“bC收到RW操作信号,将该失效信号存入“失效队列”,紧接着读取该Cache Line,该Cache Line的状态仍为S,故而不会重新加载,最终读取到旧值”,“cC收到RW操作信号,将该失效信号存入“失效队列”,然后取出该失效信号并生效,即将Cache Line的状态置为I,紧接着读取该Cache Line,由于该Cache Line的状态为I,重新加载,但是此时aC对aA的修改仍然存放在“写缓冲器”,状态也为S,故最终读取到旧值”

二、扩展

2.1、与“可见性”的关系

如上所述,上述高速缓存-写缓冲器-失效队列+MESI协议机制,“狭义可见性”问题不可避免,只能通过添加合适的内存屏障加以解决。

2.2、与“原子性”的关系

MESI协议,只能用来保证多CPU/CPU核内的高速缓存一致性,并不能帮助使得汇编指令是原子的。比如“现有CPU核A和B,执行相同的‘自增1’汇编指令C,可分别以AC和BC代指,C所涉及的变量V在Cache Line D上,可分别以AD/AV和BD/BV代指,假定AV和BV的初始值为0,并发执行AC和BC,由于AD和BD并未被缓存锁定(也没有内存总线锁的锁定,在X86指令架构中,LOCK指令前缀会发出#LOCK信号,即“内存总线锁信号”),因此AC和BC获取得到的AV和BV的值可能都为0,此时AC和BC的执行结果都为1,最终变量V在内存中的值为1,这与AC和BC原子化执行的效果不等价,在整个过程中,MESI协议正常工作但是并没有帮助使得AC和BC的执行是原子的,否则AC和BC的执行结果应该是1/2或者2/1”。


参考文献

[1]https://blog.csdn.net/qq_30055391/article/details/84892936
[2]https://stackoverflow.com/questions/29880015/lock-prefix-vs-mesi-protocol
[3]https://zhuanlan.zhihu.com/p/146374416
[4]https://juejin.im/post/6844903927654121486

您的支持将鼓励我继续分享!