std atomic同步:非原子变量为何无过期数据?是否源于acquire操作?
为什么消费者线程中的非原子变量
data不会出现过期数据? 这个问题问到点子上了——这正是C++原子操作中std::memory_order_release和std::memory_order_acquire配对的核心作用:在生产者和消费者线程之间建立严格的同步关系,保证非原子变量的可见性。
核心原理:Release-Acquire 同步规则
C++内存模型里的happens-before(先行发生)关系是关键:当一个线程用release语义存储原子变量,另一个线程用acquire语义加载到该变量的新值时,存储线程中所有在release操作之前的写操作,对加载线程中所有在acquire操作之后的读操作都是可见的。
对应到你的代码分析
我们拆解一下代码里的执行逻辑:
生产者线程:
- 先执行
data = 42;(非原子变量写操作) - 再执行
ptr.store(p, std::memory_order_release);(原子变量的release存储)
这里的release语义会强制: - 编译器和CPU不能把
data=42的写操作重排到ptr.store之后 - 同时会把
data的新值同步到其他线程可访问的内存区域(比如刷新CPU缓存)
- 先执行
消费者线程:
- 循环执行
ptr.load(std::memory_order_acquire)直到读到非空指针 - 之后执行
assert(data == 42);(非原子变量读操作)
这里的acquire语义会强制: - 编译器和CPU不能把
assert(data==42)的读操作重排到ptr.load之前 - 同时会确保加载到
ptr的新值时,生产者所有在release之前的写操作结果(包括data=42)都能被当前线程看到
- 循环执行
这就形成了一条清晰的同步链:data = 42 → 先行于 → ptr.store(release) → 同步于 → ptr.load(acquire) → 先行于 → assert(data == 42)
根据C++内存模型的规则,这条链保证了消费者读到的data一定是生产者写入的42,绝不会出现过期数据。
反例:如果没有Release-Acquire配对
如果把store和load的内存序换成std::memory_order_relaxed,那同步关系就不存在了:
- 编译器可能把
data=42重排到ptr.store之后 - CPU缓存也可能不同步,导致消费者读到
ptr的新值时,data的新值还没传到消费者的缓存
这时候assert(data==42)就可能触发,读到初始的垃圾值。
内容的提问来源于stack exchange,提问作者Antoine Morrier
相关产品推荐
相关产品推荐

