STLR(B) 是否在 ARM64 上提供顺序一致性?

Dan*_*ica 8 c++ x86-64 atomic memory-model arm64

对于在原子数据类型(例如std::atomic<uint8_t>)的对象上执行的存储,GCC 生成:

  • MOV释放存储( )情况下的指令std::memory_order_release
  • XCHG顺序一致存储情况下的指令( std::memory_order_seq_cst)。

当目标架构为 x86_64 时。然而,当是ARM64(AArch64)时,在这两种情况下,GCC都会生成相同的指令,即STLRB. 没有生成其他指令(例如内存屏障),Clang 也会发生同样的情况。这是否意味着这条被描述为具有存储-释放语义的指令实际上也提供了顺序一致性?

例如,如果在两个内核上运行的两个线程将执行STLRB不同内存位置的存储,那么这两个存储的顺序是否唯一?这样所有其他线程都保证遵守相同的顺序吗?

我之所以问,是因为根据这个答案,使用acquire-loads ,不同的线程可能会观察到不同的release-store顺序。为了观察相同的顺序,需要顺序一致性。

现场演示: https: //godbolt.org/z/hajMKnd53

Pet*_*des 11

是的,stlr是存储发布本身,并且ldar不能传递较早的stlr(即没有 StoreLoad 重新排序)-它们之间的交互满足了 acq / rel 没有的 seq_cst 要求的一部分。(ARMv8.3ldapr就像ldar没有这种交互一样,只是一个简单的获取负载,允许更高效的 acq_rel。)

所以在ARMv8.3上,seq_cst和acq/rel的区别在于负载端。8.3 之前的 ARMv8 无法执行 acq / rel,同时仍允许 StoreLoad 重新排序,因此不幸的是,如果您在发布存储之后获取加载其他内容,速度会很慢。ARMv8.3ldapr修复了这个问题,使 acq / rel 与 x86 上一样高效。

在 x86 上,一切都是获取加载或释放存储(因此 acq_rel 是免费的),实现顺序一致性的最不坏的方法是对 seq_cst 存储执行完全屏障。(您希望原子加载便宜,并且代码通常使用默认的 seq_cst 内存顺序。)

C/C++11 到处理器的映射讨论了如果您必须选择加载或存储来附加完整屏障,则需要廉价加载的权衡。)


另外, ARMv8 内存模型保证了IRIW 试金石测试(所有线程都同意独立存储的顺序),即使对于宽松的存储也是如此。它保证是“多副本原子”,这意味着当存储对任何其他核心可见时,它同时对所有其他核心可见。这足以让所有核心就所有存储的总顺序达成一致,以达到它们可以通过两个获取负载观察到的任何内容的限制。

实际上,这意味着存储只有通过提交到 L1d 缓存才变得可见,这是一致的。例如,不是通过共享物理核心的逻辑核心之间的存储转发,而是在少数 POWER CPU 上进行 IRIW 重新排序的机制,可以在现实生活中产生效果。ARMv8 最初在纸面上允许这样做,但没有 ARM CPU 这样做过。他们强化了内存模型,只是为了保证未来的 CPU 不会出现这样的奇怪情况。有关详细信息,请参阅简化 ARM 并发:ARMv8 的多副本原子公理和操作模型

请注意,所有线程能够就订单达成一致的这种保证适用于ARM64 上的所有存储,包括宽松的存储。(在具有一致共享内存的机器中,很少有硬件机制可以创建它,因此只有在罕见的 ISA 上,seq_cst 才必须实际执行任何特定操作来阻止它。)

x86 的 TSO(Total Store Order)内存模型在名称中具有所需的产权。是的,它要强大得多,基本上是程序顺序加上带有存储转发的存储缓冲区。(因此,这允许 StoreLoad 重新排序,并且允许核心在全局可见之前查看自己的存储,但仅此而已。忽略 NT 存储,以及从 WC 内存(例如视频 RAM)加载 NT...)