这种重新排序测试称为 IRIW(Independent Readers,Independent Writers),我们在其中检查两个阅读器是否可以看到同一对商店以不同的顺序出现。相关的,可能是重复的:Acquire/release semantics with 4 threads
正如@MWid 的回答所说,非常弱的 C++11 内存模型不需要所有线程就存储的全局顺序达成一致。
该答案将解释一种可能的硬件机制,该机制可能导致线程对存储的全局顺序存在分歧,这在为无锁代码设置测试时可能相关。只是因为如果你喜欢 cpu-architecture 1会很有趣。
有关这些 ISA 的抽象模型,请参阅A Tutorial Introduction to the ARM and POWER Relaxed Memory Models:ARM 和 POWER 都不保证所有线程都可以看到一致的全局存储顺序。 实际上,在 POWER 芯片上的实践中观察到这一点是可能的,在 ARM 上理论上可能是可能的,但在任何实际实现中可能都没有。
(我认为,其他弱排序的 ISA ,如 Alpha也允许这种重新排序。ARM 曾经允许它在纸上进行重新排序,但可能没有真正的实现做过这种重新排序。ARMv8 甚至加强了他们的纸上模型,即使对于未来的硬件也不允许这样做。 )
在计算机科学中,存储同时对所有其他线程可见(因此存在单一全局存储顺序)的机器的术语是“多拷贝原子”或“多拷贝原子”。x86 和 SPARC 的 TSO 内存模型具有该属性,但 ARM 和 POWER 不需要它。
当前的 SMP 机器使用MESI来维护单个一致的缓存域,以便所有内核具有相同的内存视图。当存储从存储缓冲区提交到 L1d 缓存时,它们将成为全局可见的。此时,来自任何其他核心的负载都会看到该存储。因为MESI维护一个单一的一致性域,所以所有存储都提交缓存的顺序是单一的。有了足够的障碍来阻止本地重新排序,就可以恢复顺序一致性。
在全局可见之前,商店可以对某些但不是所有其他核心可见。
POWER CPU 使用同步多线程 (SMT)(超线程的通用术语)在一个物理内核上运行多个逻辑内核。我们关心的内存排序规则是针对线程运行的逻辑内核,而不是物理内核。
我们通常认为加载是从 L1d 获取它们的值,但是当从同一个核心重新加载最近的存储并且数据直接从存储缓冲区转发时,情况并非如此。(存储到加载转发,或 SLF)。负载甚至有可能获得一个在 L1d 中从未出现过的值,并且即使在具有部分 SLF 的强排序 x86 上也永远不会出现。(请参阅我对Globally Invisible load instructions的回答)。
存储缓冲区在存储指令退出之前跟踪推测存储,但也在它们从内核的无序执行部分(ROB / ReOrder 缓冲区)退出后缓冲非推测存储。
同一物理内核上的逻辑内核共享一个存储缓冲区。推测性(尚未退役)存储必须对每个逻辑核心保持私有。(否则,这会将他们的推测结合在一起,并且如果检测到错误推测,则要求两者都回滚。这将破坏 SMT 的部分目的,即在一个线程停止或从分支错误预测中恢复时保持核心忙碌) .
但是我们可以让其他逻辑核心窥探存储缓冲区的非推测性存储,这些存储最终肯定会提交到 L1d 缓存。在他们这样做之前,其他物理内核上的线程无法看到它们,但共享相同物理内核的逻辑内核可以。
(我不确定这是否正是允许 POWER 出现这种奇怪现象的硬件机制,但这是合理的)。
这种机制使存储在对所有内核全局可见之前对 SMT 同级内核可见。但它仍然在核心内是本地的,因此这种重新排序可以通过只影响存储缓冲区的障碍来廉价地避免,而不会实际强制核心之间的任何缓存交互。
(在 ARM/POWER 论文中提出的抽象内存模型将此建模为每个内核都有自己的内存缓存视图,缓存之间的链接可以让它们同步。但在典型的现代物理硬件中,我认为唯一的机制是在 SMT 兄弟之间,而不是在单独的核心之间。)
请注意,x86 根本不允许其他逻辑内核窥探存储缓冲区,因为这会违反 x86 的 TSO 内存模型(通过允许这种奇怪的重新排序)。作为我对在一个带有 HT 的核心上执行的线程之间的数据交换将使用什么的回答?解释说,带有 SMT(英特尔称之为超线程)的英特尔 CPU 在逻辑内核之间静态划分存储缓冲区。
脚注 1:C++ 或特定 ISA 上的 asm 的抽象模型是您真正需要知道的关于内存排序的推理。
没有必要了解硬件细节(并且可能会导致您陷入认为某些事情是不可能的陷阱,因为您无法想象它的机制)。