是的,排序仍然适用于编译器优化。
此外,在 x86 上“原子加载操作始终相同”并不完全准确。
在 x86 上,完成的所有加载都mov
具有获取语义,并且完成的所有存储都mov
具有释放语义。所以acq_rel、acq 和relaxed 加载都是simple mov
s,acq_rel、rel 和relaxed 存储类似(acq 存储和rel 加载总是等于relaxed)。
然而,这对于 seq_cst 不一定是正确的:架构不保证seq_cst 的语义mov
。事实上,x86 指令集没有任何特定指令用于顺序一致的加载和存储。只有 x86 上的原子读取-修改-写入操作才会具有 seq_cst 语义。因此,您可以通过执行lock xadd
参数为 0 的 fetch_and_add 操作(指令)来获得加载的 seq_cst 语义,并通过执行 seq_cst 交换操作(xchg
指令)并丢弃先前的值来获得存储的 seq_cst 语义。
但你不需要两者都做!只要所有 seq_cst 存储都用 完成xchg
,seq_cst 加载就可以简单地用mov
. 双重的,如果所有的加载都是用 完成的lock xadd
,seq_cst 存储可以简单地用mov
.
xchg
并且lock xadd
比 慢得多mov
。因为程序的负载(通常)比存储多,所以使用 seq_cst 存储很方便,这样xchg
(更频繁的) seq_cst 负载可以简单地使用 a mov
。此实现细节在 x86 应用程序二进制接口 (ABI) 中进行了编码。在 x86 上,兼容的编译器必须编译 seq_cst 存储,xchg
以便可以使用更快的mov
指令完成 seq_cst 加载(可能出现在另一个翻译单元中,使用不同的编译器编译)。
因此,一般来说,seq_cst 和获取加载在 x86 上使用相同的指令完成是不正确的。这是正确的,因为 ABI 指定 seq_cst 存储被编译为xchg
.