确认对C++ memory order/acquire-release语义及代码注释的理解
先给出完整代码:
#include <atomic> #include <thread> #include <iostream> #include <chrono> std::atomic<int> data(0); std::atomic<int> data2(0); std::atomic<bool> ready(false); void producer() { data.store(42, std::memory_order_relaxed); // (1) this instruction is guaranteed to execute before ready.store ready.store(true, std::memory_order_release); data2.store(28, std::memory_order_relaxed); // (2) the compiler could decide to execute this instruction before ready.store } void consumer() { int value2 = data2.load(std::memory_order_relaxed); // (3) the compiler could decide to execute this instruction after ready.load while (!ready.load(std::memory_order_acquire)) { } int value = data.load(std::memory_order_relaxed); // (4) this instruction is guaranteed to execute after ready.load std::cout << "Consumed value: " << value << std::endl; std::cout << "Consumed value 2: " << value2 << std::endl; } int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0; }
以下是对4条注释的正确性验证:
(1) 注释正确
data.store(42, std::memory_order_relaxed) 一定会在 ready.store(true, std::memory_order_release) 之前执行。
根据C++内存模型,release语义的存储操作会禁止当前线程中所有在它之前的内存操作被重排到它之后。虽然data.store是relaxed语义,但它在程序顺序上位于release操作之前,编译器和CPU都不能将它重排到ready.store之后,因此这条注释的描述成立。
(2) 注释正确
编译器确实可以将 data2.store(28, std::memory_order_relaxed) 重排到 ready.store(true, std::memory_order_release) 之前执行。
release语义仅约束它之前的操作不能被重排到它之后,对它之后的操作没有限制。data2.store是relaxed语义,程序顺序上在release操作之后,编译器和CPU可以自由调整它的执行顺序到release操作之前(只要符合as-if规则,不影响单线程执行结果),因此这条注释的描述成立。
(3) 注释正确
编译器确实可以将 data2.load(std::memory_order_relaxed) 重排到 ready.load(std::memory_order_acquire) 之后执行。
relaxed语义的加载操作没有同步约束,和acquire语义的操作之间,只要不违反单线程的as-if规则,编译器可以调整它们的执行顺序。程序顺序上data2.load在acquire操作之前,完全可以被重排到之后执行,因此这条注释的描述成立。
(4) 注释正确
data.load(std::memory_order_relaxed) 一定会在 ready.load(std::memory_order_acquire) 之后执行。
根据C++内存模型,acquire语义的加载操作会禁止当前线程中所有在它之后的内存操作被重排到它之前。data.load在程序顺序上位于acquire操作之后,编译器和CPU都不能将它重排到ready.load之前,因此这条注释的描述成立。
内容的提问来源于stack exchange,提问作者FantaBlack28

