《C++并发编程实战(第2版)》std::memory_order_relaxed示例正确性疑问
关于std::memory_order_relaxed示例输出的解释
先贴出《C++并发编程实战(第2版)》5.6节的核心示例代码(简化版):
#include <atomic> #include <thread> std::atomic<int> x{0}, y{0}; std::atomic<int> r1{0}, r2{0}; void thread1() { r1 = y.load(std::memory_order_relaxed); // 读y x.store(5, std::memory_order_relaxed); // 写x } void thread2() { r2 = x.load(std::memory_order_relaxed); // 读x y.store(4, std::memory_order_relaxed); // 写y }
书中提到的一种合法输出对应你描述的“线程1写x=5时读到y值、线程2写y=4时读到x值”的矛盾场景(你可能记错了初始值或变量值,但核心逻辑一致)。
核心特性:std::memory_order_relaxed的本质
std::memory_order_relaxed是C++内存模型中最弱的原子操作语义,仅保证操作本身的原子性,没有任何线程间的内存序约束:
- 编译器或CPU可以对单个线程内的relaxed原子操作随意重排(只要不破坏单线程的逻辑正确性);
- 不建立线程间的
happens-before关系; - 一个线程的relaxed操作结果,对其他线程的可见性是异步且无顺序保证的。
为何“矛盾”输出合法
你提到的看似逻辑冲突的输出,是两个因素共同作用的结果:
- 指令重排:比如线程1的代码逻辑是先读
y再写x,但编译器/CPU可能将其重排为先写x再读y;线程2的逻辑是先读x再写y,实际执行时被重排为先写y再读x。由于relaxed不禁止这种重排,完全符合C++标准。 - 缓存异步同步:多CPU核心各自拥有独立缓存,relaxed原子操作的结果不会立即同步到所有核心。线程1读到的
y值可能是线程2已经写入但还未同步到线程1核心缓存的最新值,反之亦然。
为何Windows 10环境下测不到该结果
Windows主流的x86/x64架构属于强内存模型,对指令重排的限制远多于ARM、PowerPC等弱内存模型架构:
- x86/x64默认禁止写操作重排到读操作之前,也禁止读操作重排到写操作之后(针对不同内存地址的操作);
- x86/x64的原子操作默认带有类似
acquire/release的部分约束,进一步缩小了relaxed操作的重排空间。
因此在x86/x64平台上,这种极端输出的出现概率极低,几乎无法复现。如果要验证,建议在弱内存模型的架构(如ARM)上测试,或者通过编译器的高优化选项(如-O3)放大重排概率。
内容的提问来源于stack exchange,提问作者coneco
相关产品推荐
相关产品推荐

