为何std::atomic_ref要求无条件独占访问?
ISO/IEC 14882:2020 [atomics.ref.generic] p3
当存在引用*ptr对象的atomic_ref实例时,对该对象的所有访问必须仅通过这些atomic_ref实例进行。
这条规则禁止了一些看似安全的操作,比如:
- 即使通过互斥锁等机制与
std::atomic_ref的访问同步,也不能对目标对象执行非原子操作。 - 哪怕所有
std::atomic_ref的访问都是只读的,也不允许对目标对象执行非原子的只读操作。
为什么这些行为无法被定义为合法?
核心原因是硬件内存模型约束与C++标准对原子操作的一致性要求:
缓存一致性与内存可见性问题
非原子操作不会触发强制的缓存同步或内存屏障。即便用互斥锁同步,std::atomic_ref的原子操作自身带有内存顺序语义,可能绕过互斥锁的同步逻辑,导致非原子操作读取到过期的缓存值,或写入内容无法被其他线程的原子操作及时感知,引发数据竞争或状态不一致。破坏原子操作的内存顺序语义
std::atomic_ref的操作遵循明确的内存顺序(如memory_order_seq_cst、memory_order_acquire),而非原子操作完全不遵守这些语义。混合使用会打破标准定义的原子操作同步关系,导致编译器无法生成符合内存模型的代码,出现指令重排序等未定义行为。编译器优化的假设冲突
编译器会基于"对象要么全原子访问,要么全非原子访问"的假设做优化。混合访问时,编译器可能错误地将非原子读取缓存到寄存器,忽略std::atomic_ref操作带来的内存变化,导致程序行为偏离预期。
举个典型场景:线程A用std::atomic_ref<int>原子更新变量x,线程B用非原子方式读取x。即便加了互斥锁,编译器可能把线程B的非原子读取优化为单次寄存器读取,完全不感知线程A的原子写入,最终得到错误结果。
这些看似无害的操作本质上会破坏C++内存模型的一致性,因此被标准明确禁止。
内容的提问来源于stack exchange,提问作者iDingDong

