IRIW场景下C++原子操作多线程无输出的根本原因问询
IRIW场景下双线程无打印现象的根因解释
你提到的是典型的独立读独立写(Independent Read Independent Write, IRIW) 内存序问题,你猜测的编译器重排序不是该现象的根本原因,具体逻辑如下:
先明确基础语义约束
首先你对acquire内存序的重排序规则理解有误:std::memory_order_acquire的语义是禁止本线程内排在acquire操作之后的所有读写操作,被重排到acquire操作之前执行。所以func_4中while循环的y.load(std::memory_order_acquire),一定发生在后续的x.load(std::memory_order_acquire)之前,编译器不可能把这两个load操作重排,你的猜想不成立。
真实根因:跨核心的存储可见性顺序差异
release-acquire的同步机制,只能保证「发起release写的线程,在该写操作之前的所有本线程操作,对执行对应acquire读的线程可见」,但它完全不保证不同线程看到的多个独立release写操作的全局顺序是一致的。
你假设的「func1写x → func3读到x → func2写y → func4读到y」是上帝视角的全局执行顺序,但在弱内存模型硬件(如ARM、PowerPC)上,不同核心的缓存一致性传播可以存在顺序差异:
- 运行func3的核心,先观测到x的release写入,后观测到y的release写入
- 运行func4的核心,先观测到y的release写入,后观测到x的release写入
此时就会触发你提到的双线程无打印现象:
- func3退出while循环时,已经观测到x=true,但此时还没观测到y的写入,所以if判断y.load返回false,不打印
- func4退出while循环时,已经观测到y=true,但此时还没观测到x的写入,所以if判断x.load返回false,也不打印
复现与修复方案
- 该现象完全符合C++标准对release/acquire内存序的语义约束,在弱内存模型硬件上可以稳定复现
- 如果要禁止该现象,需要把所有原子操作的内存序替换为
std::memory_order_seq_cst,该内存序会强制所有线程看到的所有seq_cst操作的全局顺序完全一致,保证两个线程中至少有一个会打印输出。
相关复现代码
std::atomic<bool> x,y; void func_1() { x.store(true, std::memory_order_release); } void func_2() { y.store(true, std::memory_order_release); } void func_3() { while(!x.load(std::memory_order_acquire)); if(y.load(std::memory_order_acquire)) { std::cout << "x == true then also y == true \n"; } } void func_4() { while(!y.load(std::memory_order_acquire)); if(x.load(std::memory_order_acquire)) { std::cout << "y == true then also x == true \n"; } }
内容的提问来源于stack exchange,提问作者Kenneth
相关产品推荐
相关产品推荐

