memory_order 通过非常量左值传递时更改为默认值
memory_order changes to default when passed by non-const lvalue
#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 [=12=]x2a,0x200b5a(%rip) # 0x601024 <val>
0x00000000004004ca <+10>: xor %eax,%eax
0x00000000004004cc <+12>: retq
没有特殊的 CPU 指令来处理 x86 上预期的 std::memory_order_relaxed
排序的原子。
但是,当从 my_order
中删除 const
限定符时
auto my_order = std::memory_order_relaxed; // non-const lvalue
编译器生成的程序集变为:
0x00000000004004c0 <+0>: movl [=14=]x2a,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
,这是表达顺序一致性的 clang 方式。
什么可以解释差异?
通常,当编译器无法证明排序参数在编译时已知时,它不会冒险并假设最坏的情况。
如果 my_order
是非 const
全局变量,编译器无法知道执行 store
时的实际值是什么,因此它将使用std::memory_order_seq_cst
。
如果变量声明为const
,排序参数将生效,mfence
指令消失。
#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 [=12=]x2a,0x200b5a(%rip) # 0x601024 <val>
0x00000000004004ca <+10>: xor %eax,%eax
0x00000000004004cc <+12>: retq
没有特殊的 CPU 指令来处理 x86 上预期的 std::memory_order_relaxed
排序的原子。
但是,当从 my_order
const
限定符时
auto my_order = std::memory_order_relaxed; // non-const lvalue
编译器生成的程序集变为:
0x00000000004004c0 <+0>: movl [=14=]x2a,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
,这是表达顺序一致性的 clang 方式。
什么可以解释差异?
通常,当编译器无法证明排序参数在编译时已知时,它不会冒险并假设最坏的情况。
如果 my_order
是非 const
全局变量,编译器无法知道执行 store
时的实际值是什么,因此它将使用std::memory_order_seq_cst
。
如果变量声明为const
,排序参数将生效,mfence
指令消失。