无内存栅栏的relaxed内存序原子操作能否被优化?volatile能否修复?
1. 编译器能否优化thread1中的relaxed store操作,导致thread2无限循环?
不能。根据C++标准[intro.execution]/12的规定:
A side effect is a change in the state of the execution environment, or an interaction with the execution environment that is specified by the program. [...] The execution of a function that has side effects is not sequenced before the execution of another function unless the execution of the former is sequenced before the execution of the latter.
原子变量的store操作属于程序指定的副作用,编译器无权消除这类有明确副作用的操作。因此flag.store(true, std::memory_order_relaxed)必须被执行,不会被优化掉,thread2最终会看到这个写入操作。
2. 编译器能否将thread2中的relaxed load缓存到寄存器,导致无限循环?
不能。根据C++标准[atomics.general]/3的规定:
Atomic operations are indivisible with respect to all other atomic operations that operate on the same object. [...] Atomic operations shall not be reordered with respect to each other except as specified by the memory_order arguments.
同时,循环条件的语义要求每次迭代前都要重新计算([stmt.iter]/1)。对于原子变量的load操作,即使是memory_order_relaxed,编译器也必须保证每次load都实际读取原子对象的当前值,不能将循环内的load提升到循环外缓存到寄存器中。因为其他线程可能修改该原子变量,编译器无法假设其值在循环期间保持不变,因此thread2不会因这种优化陷入无限循环。
3. 使用volatile std::atomic<bool> flag;能否解决问题?
这属于冗余操作,因为原本的问题并不存在。std::atomic本身已经强制编译器不对其访问进行优化,确保每次原子操作都能感知到其他线程的修改。根据C++标准[dcl.type.volatile]/6:
volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation.
std::atomic的语义已经覆盖了volatile的优化限制,添加volatile不会带来额外的好处,也不需要用它来解决上述不存在的问题。
内容的提问来源于stack exchange,提问作者WaltK

