#include <atomic>
std::atomic<int> val{1};
const auto my_order = std::memory_order_relaxed; // const lvalue
int main()
{
val.store(42, my_order);
}
此代码没有任何相关性,但我注意到有关内存排序的一些奇怪内容。编译器为main生成以下程序集(x86_64,g ++ 6.2.1,使用-O3编译):
0x00000000004004c0 <+0>: movl $0x2a,0x200b5a(%rip) # 0x601024 <val>
0x00000000004004ca <+10>: xor %eax,%eax
0x00000000004004cc <+12>: retq
没有特殊的CPU指令来处理x86上预期的std::memory_order_relaxed
排序的原子
但是,从const
my_order
限定符时
auto my_order = std::memory_order_relaxed; // non-const lvalue
编译器生成的程序集变为:
0x00000000004004c0 <+0>: movl $0x2a,0x200b5a(%rip) # 0x601024 <val>
0x00000000004004ca <+10>: xor %eax,%eax
0x00000000004004cc <+12>: mfence
0x00000000004004cf <+15>: retq
mfence
指令似乎表明现在使用std::memory_order_seq_cst
排序(默认值)。这对我来说有点令人惊讶。尽管my_order
是左值(非常规地指定内存排序),但它是按值传递的(仍为std::memory_order_relaxed
)并且我不知道非const
将如何改变结果。我无法在库头文件中找到特定的重载。
使用clang我看到类似的结果,除了它使用xchg
,这是表达顺序一致性的铿锵方式。
有什么可以解释这个区别?
答案 0 :(得分:0)
作为一项规则,当编译器无法证明在编译时已知订购参数时,它将不会采取任何机会并假设最坏情况。
如果my_order
是非const
全局变量,编译器无法知道执行store
时实际值是什么,因此它将使用{{ 1}}。
如果变量声明为std::memory_order_seq_cst
,则排序参数将生效,const
指令消失。