是否需要内存屏障是因为CPU乱序执行还是因为缓存一致性问题?

con*_*ong 1 x86 arm cpu-architecture memory-barriers cpu-cache

我想知道为什么需要内存屏障,我已经阅读了一些关于这个主题的文章。
有人说这是因为cpu乱序执行,而另一些人说这是因为缓存一致性问题,存储缓冲区和无效队列导致。
那么,需要内存屏障的真正原因是什么?cpu乱序执行或者缓存一致性问题?或两者?cpu乱序执行和缓存一致性有关系吗?x86和arm有什么区别?

Pet*_*des 5

当 ISA 的内存排序规则弱于算法所需的语义时,您需要障碍来排序此核心/线程对全局可见的一致缓存的访问。

缓存始终是一致的,但这与一致性(多个操作之间的排序)是不同的。

您可以在有序的 CPU 上对内存进行重新排序。更详细地说,如何通过按顺序提交进行加载->存储重新排序?展示了如何在开始按程序顺序执行指令的管道上进行内存重新排序,但具有允许命中未命中的缓存和/或允许 OoO 提交的存储缓冲区。

有关的:


另请参阅https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/https://preshing.com/20120930/weak-vs-strong-memory-models了解更多基础知识。x86 具有“强大”的内存排序模型:程序顺序加上具有存储转发功能的存储缓冲区。C++acquirerelease“免费的”,只有原子 RMW 和 seq_cst 存储需要屏障。

ARM 具有“弱”内存排序模型:只有 C++ memory_order_consume(数据依赖排序)是“自由”的,获取和释放需要特殊指令(如ldar/ stlr)或屏障。

  • @cong:此外,这样的CPU必须证明在执行存储之前没有中间指令可能会出错。一旦一家商店在全球范围内可见,如果您发现错误猜测,您就无法“收回它”。执行 OoO exec 的正常方法是行不通的;它依靠存储缓冲区来保持非退休(推测)存储的私有性,直到确定之前的指令没有发生故障为止。(即,当存储指令从 ROB 中退出时,存储缓冲区条目“毕业”并且有资格提交到 L1d 缓存。在退出之前,一切都被视为推测) (3认同)
  • @cong:如果它仍然有一个存储缓冲区,那么是的,您需要一个“mfence”屏障(或锁定指令)来实现顺序一致性。NT 商店大多毫无意义,因此“sfence”大概没有用处。大多数代码不需要它,acq_rel 就可以了。只有双重检查锁定之类的东西才重要。缓存与需要内存屏障无关,正如我所说,它是一致的。 (2认同)
  • @cong:嗯,我想没有存储缓冲区的 x86 CPU 仍然有可能允许在稍后加载后乱序*执行*存储。这样的 CPU 是完全不切实际的。存储缓冲区是获得大量性能的廉价方法。在允许任何内存重新排序的内存模型中,如果不将 exec 与缓存/内存解耦,OoO exec 会造成巨大的资源浪费。成为 x86 意味着 OoO exec 受到强大的内存排序规则的限制,没有存储缓冲区来将 exec 与可见性分离。在现实生活中,即使是简单的有序 CPU 也有存储缓冲区。 (2认同)