Memory_order在由非const左值传递时变为default
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 $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
,这是clang表示顺序一致性的方式。如何解释这种差异呢?
作为一项规则,当编译器不能证明排序参数在编译时是已知的时,它将不会冒险并假设最坏情况。
如果my_order
不是const
全局变量,编译器无法知道store
执行时的实际值是多少,因此它将使用std::memory_order_seq_cst
。如果变量声明为const
,则排序参数将生效,mfence
指令将消失。
相关文章:
- 为什么可以将左值传递给"std::async",即使它引用了右值
- 当值传递给C++中的运算符重载函数时会发生什么
- 如何将非可变参数值传递给 fmt::format?
- 将 qml 项目值传递给 cpp 后如何与它们进行交互?
- NDK:将文本字段值传递给 c++ 字符串
- 如何将值传递给 lambda 函数
- 如何在C++中将std::string值传递给RegSetValueEx()
- 如何将 c ++ 变量的值传递给 hadoop HDFS 的 bash 系统命令?
- C++ 通过参数将值传递给 char 数组
- 如何将值传递给MFC消息映射函数on_command
- 使用JNI将长值传递给Java
- 如何在不使用 Argv 和 Argc 的情况下将 Sum 值传递给 C++ 程序
- C++ 将值传递给 fStream
- 如何将函数中的多个值传递给C++中的不同函数
- 将多个解析值传递给 addPositionalArgument 函数
- C++为什么将左值传递给move构造函数对模板有效
- 一种自动检测对象的方法,该方法通过值传递给c++中的函数
- 将值传递给main(int,char**)
- 将大于long类型的最大值的值传递给C中的fseek
- 将值传递给atexit