多Release与单Acquire场景下内存序的判定及断言有效性疑问
原子内存序与断言行为分析
示例代码
#include <atomic> #include <thread> #include <cassert> #include <memory> int i = 0; std::atomic_int a{0}; int main() { std::thread thr1{[] { i = 1; // A a.store(1, std::memory_order::release); // B }}; std::thread thr2{[] { while (a.load(std::memory_order::relaxed) != 1); // C a.store(2, std::memory_order::release); // D }}; std::thread thr3{[] { while (a.load(std::memory_order::acquire) != 2); // E assert(i == 1); // F }}; thr1.join(); thr2.join(); thr3.join(); }
你的理解完全正确
断言确实可能成功也可能失败,行为未定义,具体原因如下:
1. 先行发生关系的局限性
已确定的先行发生(happens-before)关系仅存在于:
- 线程1内部:A(写入
i=1)→ B(release语义存储a=1) - 线程2内部:C(relaxed语义加载
a)→ D(release语义存储a=2) - 线程3内部:E(acquire语义加载
a=2)→ F(断言i==1) - 跨线程:D与E之间存在release-acquire同步,因此D→E属于先行发生关系
但B与C之间不存在任何同步关系:C是relaxed加载,这类操作不提供跨线程的先行发生保证,即便线程2的C读到了线程1的B写入的1,也无法推导出B→C的先行发生关系,线程1中A对i的写入无法同步到线程2。
2. 释放序列规则不适用
关于release-acquire同步的扩展规则(释放序列后续值的同步)要求:后续操作必须是**读-改-写(RMW)**操作(如fetch_add、compare_exchange_strong等)。而线程2的D是单纯的store操作,不属于RMW,因此B到D构不成释放序列,该规则无法生效。
线程3的E仅能保证看到线程2中D之前的操作,无法通过D传递线程1中A的写入,因此执行F时i可能仍为初始值0,断言可能触发失败。
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

