看下面代码:
#include <iostream> #include <thread> #include <assert.h> #include <atomic> int a = 0; std::atomic<bool> flag{ false }; void f1() { a = 1; flag.store(true, std::memory_order_release); //flag.store(true, std::memory_order_relaxed); } void f2() { while (!flag.load(std::memory_order_acquire)) //while (!flag.load(std::memory_order_relaxed)) { } assert(a == 1); } int main(void) { std::thread t2(f2); std::thread t1(f1); t1.join(); t2.join(); return 0; }1 memory_order_release要求,在调用memory_order_release之前的所有写操作,不得重排到memory_order_release之后。在上面的代码里,显然a = 1就是写入。
2 memory_order_acquire要求,在调用memory_order_acquire之后的所有读操作,不得重排到memory_order_acquire之前。在上面的代码里,a == 1是对a当前值的判断,当然属于读操作。
3 结合1与2,函数f2的while循环直到flag == true才会跳出,所以跳出之前,f1一定已经将flag.store执行完毕了。那么根据(1)的要求,a=1的操作肯定发生在flag.store之前。于是,while()循环结束后,a=1的操作一定已经发生了。再结合上一篇理解原子变量之四:可见性、memory_order_acquire与 memory_order_release_memory order acquire-CSDN博客的可见性,a的改变一定可以对此时的线程t2可见。
最后,根据(2)的要求,assert(a == 1)一定发生在while之后,因为里面含有flag.load(memory_order_acquire)。所以assert(a == 1)一定可以看到a == 1为真。
最后,建议读一下微信公众号“程序喵大人”的文章《【C++并发系列】第五章:C++ 内存模型在约束什么?》,里面的描述更加全面。