compare_exchange_strong 总是返回 false 最常见原因是 expected 与原子变量当前值不一致,函数仅在相等时才交换并返回 true;expected 总是被更新为原子变量原值,需配合循环重试或状态判断使用。

compare_exchange_strong 为什么总是返回 false
最常见原因是预期值(expected 参数)和原子变量当前值不一致,函数直接失败不修改。它不是“尝试设置”,而是“只有当前值等于 expected 才设为 desired”。很多初学者误以为它是无条件更新,结果发现 compare_exchange_strong 总是返回 false,却没检查 expected 是否被函数内部更新为当前真实值。
正确做法是配合循环重试:
std::atomic<int> counter{0};
int expected = 0;
while (!counter.compare_exchange_strong(expected, 1)) {
// expected 已被更新为 counter 当前值
// 如果还想设成 1,就继续用新值重试(或加逻辑判断)
}
compare_exchange_strong 和 compare_exchange_weak 的区别
两者语义完全一致:仅当原子变量值等于 expected 时,才将其设为 desired 并返回 true;否则将当前值写入 expected 并返回 false。关键差异在弱版本允许「伪失败」(spurious failure)——即使值匹配,也可能返回 false(常见于 LL/SC 架构如 ARM、RISC-V)。
因此:
立即学习“C++免费学习笔记(深入)”;
-
compare_exchange_weak更适合循环内使用(开销略低),但必须配合 do-while 或 while 循环 -
compare_exchange_strong适合单次尝试场景(比如初始化检查),或不想处理伪失败的代码路径 - 在 x86/x64 上二者实际生成的指令几乎一样,
_strong并不慢
带内存序参数的用法容易出错
compare_exchange_strong 有双内存序重载:compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure)。很多人只传一个序(如 memory_order_acquire),结果编译失败——因为单参数版本要求两个序相同,必须显式写出两个。
典型安全组合:
- 读-改-写场景常用:
memory_order_acq_rel(成功时) +memory_order_acquire(失败时) - 纯无锁计数器可简化为:
memory_order_relaxed+memory_order_relaxed(无同步需求时) - failure 序不能强于 success 序(例如不能 success=relaxed, failure=acquire)
漏写 failure 序或顺序颠倒会触发编译错误或未定义行为。
bool 返回值和 expected 的联动关系
返回值不是“操作是否完成”,而是“值是否匹配并完成交换”。更重要的是:expected 在调用后**总是被更新**——无论成功与否,它都会被设为原子变量调用前的瞬时值。
这意味着你可以靠它做状态推断:
std::atomic<int> flag{0};
int expected = 1;
if (!flag.compare_exchange_strong(expected, 2)) {
// 此时 expected == flag 原来的值
// 如果 expected == 0 → 原来是未设置状态
// 如果 expected == 2 → 可能是别的线程刚设过
}
这个特性常用于实现状态机或一次性初始化,但前提是必须理解 expected 是输入输出参数,不能假设它保持原值。
真正难的不是语法,是设计时想清楚「失败后怎么利用新读出的值推进逻辑」——多数 bug 出在这里,而不是调用本身写错了。


















