写缓冲器 ,无效化队列 存储屏障 加载屏障

为什么会有写缓冲器 ,无效化队列 ?

先来看一下什么是缓存一致性协议

核心思想:如果变量是共享变量,当其他CPU修改这个变量的时候,发出信号将其他CPU的变量置为失效状态,其他CPU再使用这一变量的时候会从内存中加载这一变量。

修改共享数据的时候,发现相应 缓存行的状态是S, 就是共享,说明其他cpu也有副本, 这时候要发 无效 的通知出去广播给其他cpu把缓存里面的值为无效(Invalid)状态,然后待收到各个缓存的(Invalid ack)已经完成无效状态修改的回应之后,再把自己的状态改为Exclusive,之后再进行修改,修改后再改为Modified状态,数据写入缓存行。

这样会有一个缺点,CPU需要在等待所有的Invalid ack之后才会进行下面的操作。这会让CPU产生一定的阻塞,无法充分利用CPU。这个时候就出来了写缓冲器无效队列化。


 写缓冲器

写的时候,发现相应 缓存行的状态是S, 就是共享,说明其他cpu也有副本, 这时候要发 无效 的通知出去广播给其他cpu把缓存里面的值为无效(Invalid)状态 本来是要等回复才能继续的, 有了写缓冲器 就可以先把修改的数据放到写缓冲器,然后通知等其他cpu等他们回复(ack), 这个时候不会造成线程阻塞,cpu可以利用等待的时间继续向下执行,等回复都到了以后cpu再来把数据从写缓冲器搬运到缓存行。
 
存储转发
cpu读取数据的时候先从 写缓存器读, 没有 再去 读高速缓存, 这样就可以还是读到真的数据了

无效化队列

其他cpu收到无效通知以后, 并不把数据无效化, 而是存入无效化队列 就回复 收到无效Ack,这样可以让对方早点收到回复,等cpu忙完当前的事在进行读取无效化队列。

这样会造成一些问题

  1. 存储转发:cpu0 更新了a的值, 写到写缓冲器就往下走了,过一阵,要读a,这时先去写缓存器读, 读到的自以为是最新的,但是没准这一阵时间里面, cpu1已经改过a的值了,但是, cpu1发过来的无效通知, 是管不到 cpu0的写缓冲器的。
  2. 写缓冲器:其他CPU还没有给我们回答的时候我们已经执行下一步代码了。
  3. 无效化队列:其他CPU已经给对方应答的时候自己本身还没有去把这个值改为无效状态,这样就造成当前变量已经无效,但是通知还在无效队列化中,会取到旧值。

存储屏障 加载屏障 

总之, 写缓冲器 ,无效化队列 就是导致了可见性问题, 明明写了 其他线程看不到这就需要编译器等底层系统 借助 内存屏障

存储屏障 : 让cpu 将 写缓冲器排空,写入高速缓存 这叫冲刷, 这样其他cpu 就会收到通知, 其他cpu可以来拿新数据
加载屏障:cpu 根据无效化队列里面的信息,删除其高速缓存的无效数据(就是状态变为I)

这2个屏障的成对使用, 才能保证更新可见

原文连接:https://www.jianshu.com/p/8a95094fb344

原文地址:https://www.cnblogs.com/blwy-zmh/p/12748566.html