C++20中带seq-cst栅栏的原子操作可见性疑问
C17与C20中Seq-Cst栅栏的可见性保证疑问
C++17的明确规则
C++17标准32.4 [atomics.order]第6段规定:
针对原子对象M的原子操作A(修改M)和B(读取M的值),若存在
memory_order::seq_cst栅栏X、Y,使得A先于X执行,Y先于B执行,且X在全序S中先于Y,则B会观察到A的修改效果或M修改顺序中更晚的修改。
以经典StoreLoad重排测试为例:
// Thread 1 a.store(1, std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_seq_cst); // F1 b.load(std::memory_order_relaxed); // Thread 2 b.store(1, std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_seq_cst); // F2 a.load(std::memory_order_relaxed);
如果F1在全序S中先于F2,线程2的a.load()必然能观察到线程1的a.store(1);反之若F2先于F1,线程1的b.load()也能观察到线程2的b.store(1)。这个规则直接把栅栏的全序关系和原子操作的可见性绑定,逻辑清晰。
C++20的定义困惑
C20通过P0668R5重写了相关段落,引入了coherence-ordered和seq-cst操作全序S的约束。但这里的疑问在于:新定义以A和B处于coherence-ordered为前提,而coherence-ordered本身要求B观察到A写入的值——这看起来像是把「可见性」当成了前提,而非规则要保证的结果,完全不像C17那样直接说明栅栏如何确保可见性。
解惑:C++20的逻辑闭环
你没遗漏关键信息,C20只是换了表述逻辑,最终保证和C17完全一致:
- 所有seq-cst栅栏(以及seq-cst原子操作)都属于全局一致的全序S。
- 线程内的操作顺序会约束coherence order与全序S的关系:线程1中
a.store先于F1执行,那么a.store在coherence order中的位置必须早于F1在S中的位置;同理,线程2中F2先于a.load执行,F2在S中的位置必须早于a.load在coherence order中的位置。 - 当F1在S中先于F2时,结合上述约束,
a.store的coherence order位置必然早于a.load的位置。而coherence order要求读取操作必须观察到自身之前的最后一次写入,所以a.load必然能看到a.store(1)或更晚的写入——这和C++17的保证完全等价。
简单说,C20是通过「线程内顺序绑定全局S顺序」+「coherence order的读写规则」间接实现可见性保证,而非像C17那样直接描述栅栏的作用,但最终效果完全一致。
内容的提问来源于stack exchange,提问作者mpoeter
相关产品推荐
相关产品推荐

