Meh*_*dad 10 c++ multithreading atomic memory-model c++11
考虑以下伪代码:
expected = null;
if (variable == expected)
{
atomic_compare_exchange_strong(
&variable, expected, desired(), memory_order_acq_rel, memory_order_acq);
}
return variable;
Run Code Online (Sandbox Code Playgroud)
观察执行检查时没有 "获取"语义variable == expected.
在我看来desired,总共至少会调用一次,每个线程最多调用一次.
此外,如果desired永远不会返回null,那么此代码将永远不会返回null.
现在,我有三个问题:
以上一定是真的吗?也就是说,即使在每次读取都没有围栏的情况下,我们是否真的可以对共享变量进行有序读取?
是否可以在C++中实现它?如果是这样,怎么样?如果没有,为什么?
(希望有一个理由,而不仅仅是"因为标准这样说".)
如果(2)的答案是肯定的,那么是否也可以在C++中实现它而不需要variable == expected执行原子读取variable?
基本上,我的目标是了解一旦代码被每个线程至少执行一次,是否有可能以与非共享变量相同的性能执行共享变量的延迟初始化?
(这有点像"语言 - 律师"问题.所以这意味着问题不在于这是一个好的还是有用的想法,而在于技术上是否可以正确地做到这一点.)
关于是否可以在 C++ 中执行共享变量的延迟初始化的问题,其性能(几乎)与非共享变量相同:
答案是,这取决于硬件架构、编译器的实现和运行时环境。至少,在某些环境下是可能的。特别是在带有 GCC 和 Clang 的 x86 上。
在 x86 上,原子读取可以在没有内存栅栏的情况下实现。基本上,原子读取与非原子读取相同。看一下下面的编译单元:
std::atomic<int> global_value;
int load_global_value() { return global_value.load(std::memory_order_seq_cst); }
Run Code Online (Sandbox Code Playgroud)
虽然我使用了具有顺序一致性的原子操作(默认),但生成的代码没有什么特别的。GCC 和 Clang 生成的汇编代码如下所示:
load_global_value():
movl global_value(%rip), %eax
retq
Run Code Online (Sandbox Code Playgroud)
我说几乎相同,因为还有其他原因可能会影响性能。例如:
话虽如此,实现延迟初始化的推荐方法是使用std::call_once. 这将为您提供所有编译器、环境和目标架构的最佳结果。
std::once_flag _init;
std::unique_ptr<gadget> _gadget;
auto get_gadget() -> gadget&
{
std::call_once(_init, [this] { _gadget.reset(new gadget{...}); });
return *_gadget;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
273 次 |
| 最近记录: |