|
                    
                    
                        linux
                        
                            、
                        
                    
                        计算机组成
                        
                    
                
                内存屏障随笔(memory-barrier)
             
         
        
            Store Buffer(write barrier)
MESI 协议中,如果 CPU-0 对一个块 非独占数据进行修改 会发出 Invalid 信号通知其他持有该数据的 CPU ,然后等待  CPU ACK。如果其他 CPU ACK 响应较慢,则会浪费 CPU-0 大量的 CPU时间,所以有了 Store Buffer。
处理器把它想要写入到主存的值写到缓存,然后继续去处理其他事情。当所有失效确认(Invalidate Acknowledge)都接收到时,数据才会最终被提交。但是这么做会有问题:
广播延迟,导致结果异常
下图中:
CPU 0 步驟如下:
- 写入 a 的值 (=1) 到 store buffer (但 cache 里仍是 0)
 
- 广播 “invalidate a” (异步)
 
- 改 b 的值。因为 b 的状态已是 
Modified,cacheline 的值更新成 1 
CPU 1 步骤如下:
- 本地读 b,发现是 invalid
 
- CPU-0 将 b 刷入主存
 
- 读取主存中 b 的值
 
- 此时 invalid a 广播  还没到达
 
- 读取 a 的值(此时 a 的状态是 shared,所以直接读 0)到寄存器
 
- 断言 a 的值为 1 失败(此时 a 为 0)
 

解决方案
问题出在了,store buffer 破坏了 缓存一致性(cache coherence)。于是 CPU 需要提供 write memory barrier ,让软件在必要场景(data-race)避免这个问题。
下图中:
CPU 0 步驟如下:
- 写入 a 的值 (=1) 到 store buffer (但 cache 里仍是 0)
 
- 广播 “invalidate a” (异步)
 
- write barrier 指令阻塞,直到获取 invalid ack
 
- 改 b 的值。因为 b 的状态已是 
Modified,cacheline 的值更新成 1 
CPU 1 步骤如下:(5,6)两步发生在 b 等于 1 之前
- 本地读 b,发现是 invalid
 
- CPU-0 将 b 刷入主存
 
- 读取主存中 b 的值
 
- 如果此时 b 为 0 则跳回 步骤1
 
- 收到 invalid a 广播
 
- a 设置成 invalid
 
- 发送 invalid ack 到 总线(BUS)
 
- 读取 a 的值 发现是 invalid
 
- CPU-0 将 a 刷入主存
 
- 读取主存中 a 的值(1)
 
- 断言 a 的值为 1 成功(此时 a 为 1)
 
