compare_exchange_weak 必须在循环中使用,且 expected 必须是非 const 左值引用,否则无法更新预期值导致伪失败后死锁;它允许伪失败但会将当前值写回 expected(仅当可修改时),而 compare_exchange_strong 适用于单次关键操作。

compare_exchange_weak 必须写在循环里,且 expected 必须是可修改的非 const 引用——否则几乎必然返回 false,不是因为逻辑错,而是它根本没机会更新预期值。
为什么单次调用 compare_exchange_weak 几乎总是失败
常见现象:刚声明 std::atomic<int> counter{0}</int>,写 int expected = 0; counter.compare_exchange_weak(expected, 1);,结果返回 false,但 counter 确实还是 0。
根本原因有两个:
-
compare_exchange_weak允许伪失败(spurious failure),尤其在 ARM 平台,即使值匹配也可能返回false - 它会在失败时把原子变量当前真实值写回
expected变量——但前提是expected是可写的左值引用;如果传的是字面量、临时量或const int&,这个写回就失效了
一旦 expected 没被更新,下一次重试仍拿旧值去比,永远卡住。
expected 必须是非 const 的左值,且生命周期要覆盖整个循环
compare_exchange_weak 的第一个参数签名是 T& expected,不是 const T&,也不是值传递。它靠修改这个引用所指向的内存来传递最新快照。
错误写法示例:
-
compare_exchange_weak(0, 1)→ 编译失败:不能绑定非常量引用到右值 -
compare_exchange_weak(counter.load(), 1)→ 同样编译失败 -
const int exp = counter.load(); counter.compare_exchange_weak(exp, 1);→ 即使编译通过,exp不可写,函数无法更新它,循环死锁
正确写法只有一种模式:
int expected = counter.load(std::memory_order_relaxed);
do {
int desired = expected + 1;
} while (!counter.compare_exchange_weak(expected, desired,
std::memory_order_release, std::memory_order_relaxed));
这里 expected 是普通变量,每次失败后自动被刷成 counter 当前值,下一轮循环直接用新快照构造 desired。
compare_exchange_weak 和 compare_exchange_strong 怎么选
这不是“强弱”之分,而是语义与性能的权衡:
- 循环重试场景(如无锁栈 push/pop、计数器递增)→ 优先用
compare_exchange_weak:x86/ARM 上指令更紧凑,延迟更低;伪失败由循环兜底,不增加分支开销 - 单次关键操作(如初始化标志位、金融事务提交)→ 考虑
compare_exchange_strong:它保证仅当值真实不等才失败,避免伪失败干扰业务逻辑 - 极端争用下伪失败堆积 → 可在循环内 fallback 到
strong版本,防止无限重试
注意:compare_exchange_strong 内部其实也用了循环屏蔽伪失败,只是这个循环藏在标准库实现里,你没法控制重试逻辑。
容易被忽略的 ABA 问题和内存序陷阱
指针类型 CAS(比如无锁链表节点操作)天然面临 ABA 问题:节点 A 被弹出、析构、新节点又分配到同一地址,CAS 误判“还是原来的 A”,导致链表断裂或崩溃。
这不是 compare_exchange_weak 的 bug,而是裸指针 CAS 的固有缺陷,必须显式应对:
- 加版本号:用
std::atomic<uint64_t></uint64_t>存打包的(ptr, version),CAS 时一起比 - 延迟回收:用 Hazard Pointer 或 epoch-based reclamation,确保指针复用前旧对象已不可达
内存序也常被误配:failure 路径用 std::memory_order_relaxed 就够了(没写操作),success 路径则按语义选,比如栈 push 用 std::memory_order_release,pop 用 std::memory_order_acquire。错用会引入数据竞争,且很难复现。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











