C++顺序一致性内存序全序定义及示例疑问解析
核心问题解答
1. 什么情况下assert(z.load() != 0);会触发失败?
当代码中所有std::memory_order_seq_cst替换为弱于seq_cst的内存序(比如std::memory_order_relaxed、std::memory_order_acquire/std::memory_order_release、std::memory_order_acq_rel)时,断言可能失败。
弱内存序不要求所有线程观察到全局一致的原子操作顺序:线程c(read_x_then_y)可能先观察到x被修改为true,但此时y的修改还没同步到它的缓存;同时线程d(read_y_then_x)可能先观察到y被修改为true,但x的修改还没同步到它的缓存。这种情况下两个线程都不会执行++z,最终z保持为0,触发断言失败。
2. 为何使用std::memory_order_seq_cst时,z的值永远不会为0?
std::memory_order_seq_cst是C++中最强的内存序,它强制所有线程观察到的所有seq_cst原子操作拥有全局一致的总顺序。也就是说,x.store(true)和y.store(true)这两个操作,在全局总序里必然有明确的先后:
- 如果全局总序是
x.store先于y.store:线程d等待到y变为true时,必然能观察到x已经是true,会执行++z; - 如果全局总序是
y.store先于x.store:线程c等待到x变为true时,必然能观察到y已经是true,会执行++z。
而std::memory_order_acq_rel仅保证单个线程内的操作顺序,以及原子操作的同步关系,但不强制全局一致的总顺序——不同线程可能看到x和y的修改顺序完全相反,从而出现z=0的情况。
补充困惑解析
其他内存序下,线程c和d为何会观察到x、y的修改顺序相反?
弱内存序允许CPU对内存操作进行重排序,同时缓存一致性协议不强制全局统一的操作可见性顺序。每个线程可以拥有自己的操作顺序视图:
- 线程
c的视图中,x.store先于y.store发生,但它可能在x变为true后仍看不到y的修改; - 线程
d的视图中,y.store先于x.store发生,但它可能在y变为true后仍看不到x的修改。
这种“各线程看到的操作顺序不一致”的情况,在seq_cst下是被严格禁止的。
memory_order_seq_cst是通过强制read_x_then_y中的x.load必须在y.load之前执行来解决问题的吗?
不完全是。seq_cst确实会保证单个线程内的操作遵循程序顺序(即read_x_then_y中x.load必然先于y.load执行),但更核心的是它强制了全局总序——所有线程看到的所有seq_cst原子操作的执行顺序完全一致。
即使弱内存序保证线程内的操作顺序,也可能出现不同线程观察到全局顺序相反的情况;而seq_cst通过全局总序确保:只要一个线程观察到某个seq_cst操作完成,那么所有在全局总序中先于它的seq_cst操作,这个线程都能观察到。这才是避免z=0的关键。
附示例代码
#include <thread> #include <atomic> #include <cassert> std::atomic<bool> x = {false}; std::atomic<bool> y = {false}; std::atomic<int> z = {0}; void write_x() { x.store(true, std::memory_order_seq_cst); } void write_y() { y.store(true, std::memory_order_seq_cst); } void read_x_then_y() { while (!x.load(std::memory_order_seq_cst)) ; if (y.load(std::memory_order_seq_cst)) { ++z; } } void read_y_then_x() { while (!y.load(std::memory_order_seq_cst)) ; if (x.load(std::memory_order_seq_cst)) { ++z; } } int main() { std::thread a(write_x); std::thread b(write_y); std::thread c(read_x_then_y); std::thread d(read_y_then_x); a.join(); b.join(); c.join(); d.join(); assert(z.load() != 0); // will never happen }
内容的提问来源于stack exchange,提问作者heturing

