【发布时间】:2020-08-19 14:19:52
【问题描述】:
让std::atomic<std::int64_t> num{0}; 定义在代码中可访问/可见的某个地方。
C++ 编译器是否允许将以下两个代码中的每一个替换为空代码(什么都不做)?同样,这些优化是否允许在运行时发生?
我只是想更好地了解事情的运作方式。
num.fetch_add(1,std::memory_order_relaxed);
num.fetch_sub(1,std::memory_order_relaxed);
和
num.fetch_add(1,std::memory_order_relaxed);
std::this_thread::yield();
num.fetch_sub(1,std::memory_order_relaxed);
【问题讨论】:
-
运行时不做任何优化。它们都是由编译器完成的。
-
num.fetch_add(1,std::memory_order_relaxed); num.fetch_sub(1,std::memory_order_relaxed);这不是 NOOP,因为其他人可以在操作之间访问它并对其进行处理。所以它不应该被 NOOP 取代。 Yielding 只是试图让其他线程继续执行。否则,在无限循环中读取/写入原子直到满足某些条件 - 可能会占用太多资源。 -
@ALX23z 实际上这个 is 可以用 NOOP 替换,因为它只使用 memory_order_relaxed。 JF Bastien 在N4455 No Sane Compiler Would Optimize Atomics 中提出了一个类似的例子。
-
理论上这样的优化是可能的。在实践中,编译器似乎不会这样做:godbolt.org/z/Gg2Sub
-
如果你有更强的内存顺序,它可能会阻止其他操作在 add/sub 对中重新排序,有点像
atomic_thread_fence()。 (但请注意,栅栏比单一操作更强大)。但是在放松的情况下,编译器将被允许决定每个其他线程总是看到这些背靠背并取消的顺序。请参阅我在Can num++ be atomic for 'int num'? 上的答案底部以进行讨论。请注意,volatile atomic肯定会阻止此优化。
标签: c++ multithreading c++11 stdatomic