混合条件语句与内存序的代码正确性及相关场景验证
C++内存模型相关问题解答
问题1:disabled原子变量的线程同步正确性
先看目标代码:
std::atomic_bool disabled = true; int counter1 = 0, counter2 = 1; // 线程1 while (...) { counter2 = ...; if (disabled.load(std::memory_order::acquire) && counter2 > counter1) // #1 { disabled.store(false, std::memory_order::relaxed); disabled.notify_one(); } } // 线程2 while (...) { disabled.wait(true, std::memory_order::relaxed); // 执行操作 counter1 = ...; disabled.store(true, std::memory_order::release); // #2 }
这段代码可以保证行为正确,#1处的acquire load能与#2处的release store建立同步关系,线程1能看到counter1的正确值,原因如下:
- 线程2中,
counter1 = ...先行于disabled.store(true, release)(#2),根据release语义,这个store会将counter1的写入暴露给任何后续读取到该store结果的acquire load。 - 线程1的#1是acquire load,当它读取到#2写入的
true值时,两者之间会建立release-acquire同步关系,线程1因此能看到线程2中counter1的更新。 - 线程1中
disabled.store(false, relaxed)和线程2中disabled.wait(true, relaxed)使用relaxed内存序是可行的:- 前者只是临时将
disabled设为false以通知线程2,不需要同步其他变量; - wait的relaxed内存序仅作用于它内部的load操作,但线程2后续的release store(#2)已经承担了同步
counter1的职责,wait的内存序不影响最终的release-acquire同步。
- 前者只是临时将
问题2:连续store下的release-acquire同步是否被破坏
看目标代码:
std::atomic_int a = 0; int x = 0; // 线程1 x = 1; a.store(1, std::memory_order::release); a.store(2, std::memory_order::relaxed); // 线程2 assert(a.load(std::memory_order::acquire) != 2 || x == 1);
这个断言可能失败,具体分析:
- 你的第一种猜想不成立:同一线程内的操作存在先行发生关系,
x=1先行于a.store(1, release),后者又先行于a.store(2, relaxed),编译器和CPU不会将第二次store重排到第一次之前。 - 你的第二种猜想成立:后续的relaxed store不会“破坏”之前的release-acquire关系,但会导致线程2的acquire load可能看不到release store的结果,从而失去同步:
- 线程2的acquire load如果读取到2(来自relaxed store),此时该load与线程1的release store(写入1)之间没有同步关系——因为acquire load必须读取到release store的结果才能建立同步。
- 由于没有同步,线程1中
x=1的写入对线程2可能不可见,此时断言会触发(a.load()为2,x为0)。
另外,你提到的seq_cst相关描述,是指当程序中存在非seq_cst的原子操作时,整体的顺序一致性保证会丢失,但这和本次问题中的release-acquire同步是两个独立概念,不影响本次分析。
内容的提问来源于stack exchange,提问作者Nieta
相关产品推荐
相关产品推荐

