memory_order在由非const左值传递时更改为默认值

时间:2016-11-17 00:45:18

标签: c++ c++11 memory-barriers

#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,这是表达顺序一致性的铿锵方式。
有什么可以解释这个区别?

1 个答案:

答案 0 :(得分:0)

作为一项规则,当编译器无法证明在编译时已知订购参数时,它将不会采取任何机会并假设最坏情况。

如果my_order是非const全局变量,编译器无法知道执行store时实际值是什么,因此它将使用{{ 1}}。 如果变量声明为std::memory_order_seq_cst,则排序参数将生效,const指令消失。