内存屏障随笔(memory-barrier)

Store Buffer(write barrier)

MESI 协议中,如果 CPU-0 对一个块 非独占数据进行修改 会发出 Invalid 信号通知其他持有该数据的 CPU ,然后等待 CPU ACK。如果其他 CPU ACK 响应较慢,则会浪费 CPU-0 大量的 CPU时间,所以有了 Store Buffer

处理器把它想要写入到主存的值写到缓存,然后继续去处理其他事情。当所有失效确认(Invalidate Acknowledge)都接收到时,数据才会最终被提交。但是这么做会有问题:

广播延迟,导致结果异常

下图中:

CPU 0 步驟如下:

  1. 写入 a 的值 (=1) 到 store buffer (但 cache 里仍是 0)
  2. 广播 “invalidate a” (异步)
  3. 改 b 的值。因为 b 的状态已是 Modifiedcacheline 的值更新成 1

CPU 1 步骤如下:

  1. 本地读 b,发现是 invalid
  2. CPU-0 将 b 刷入主存
  3. 读取主存中 b 的值
  4. 此时 invalid a 广播 还没到达
  5. 读取 a 的值(此时 a 的状态是 shared,所以直接读 0)到寄存器
  6. 断言 a 的值为 1 失败(此时 a 为 0)

image-20221021181741696

解决方案

问题出在了,store buffer 破坏了 缓存一致性(cache coherence)。于是 CPU 需要提供 write memory barrier ,让软件在必要场景(data-race)避免这个问题。

下图中:

CPU 0 步驟如下:

  1. 写入 a 的值 (=1) 到 store buffer (但 cache 里仍是 0)
  2. 广播 “invalidate a” (异步)
  3. write barrier 指令阻塞,直到获取 invalid ack
  4. 改 b 的值。因为 b 的状态已是 Modifiedcacheline 的值更新成 1

CPU 1 步骤如下:(5,6)两步发生在 b 等于 1 之前

  1. 本地读 b,发现是 invalid
  2. CPU-0 将 b 刷入主存
  3. 读取主存中 b 的值
  4. 如果此时 b 为 0 则跳回 步骤1
  5. 收到 invalid a 广播
  6. a 设置成 invalid
  7. 发送 invalid ack 到 总线(BUS)
  8. 读取 a 的值 发现是 invalid
  9. CPU-0 将 a 刷入主存
  10. 读取主存中 a 的值(1)
  11. 断言 a 的值为 1 成功(此时 a 为 1)

image-20221021182957483


好好学习,天天向上