compare_exchange_weak必须在循环中使用且expected为非const可修改左值引用,否则因伪失败或无法更新expected导致死循环;正确写法是int expected = atomic_var.load(); while(!atomic_var.compare_exchange_weak(expected, desired)) { }。

必须写在循环里,且 expected 必须是非 const 的可修改左值引用——漏掉任一条件,大概率死循环或逻辑错。
为什么 compare_exchange_weak 总是返回 false?
常见现象:刚初始化 std::atomic<int></int>,设 expected = 0,调一次 compare_exchange_weak(expected, 1) 就返回 false,但值明明没被改过。
原因有两个:
-
compare_exchange_weak允许伪失败(spurious failure),尤其在 ARM 等弱内存模型平台; - 它会**覆写
expected的值**为原子变量当前实际值——如果expected是字面量、临时变量或const int&,函数无法更新它,下次重试仍用旧值,导致无限失败。
✅ 正确写法:
int expected = atomic_var.load();<br>while (!atomic_var.compare_exchange_weak(expected, desired)) {<br> // expected 已被更新为当前值,可继续用<br>}
❌ 错误写法:
int expected = 0;<br>atomic_var.compare_exchange_weak(expected, 1); // 只调一次,且 expected 固定不变
❌ 危险写法:
const int exp = atomic_var.load();<br>atomic_var.compare_exchange_weak(exp, 1); // 引用绑定到 const,函数无法更新它
compare_exchange_weak 循环里该不该改 desired?
取决于你更新的语义是否依赖 expected 的“快照”值。例如递增计数器时,desired 应基于当前 expected 计算;但若只是设置固定状态(如 flag = 1),则 desired 可保持不变。
关键点:
- 循环体中不要无条件重新计算
desired(比如每次都desired = rand()),否则可能永远无法满足条件; - 避免在循环内做耗时操作(如
new、锁、IO、系统调用),CAS 循环应尽量轻量; - 极端高争用下,
weak可能反复伪失败,此时可加std::this_thread::yield()或直接切compare_exchange_strong。
指针 CAS 容易踩的 ABA 问题怎么防?
裸指针 std::atomic<node></node>*> 的 CAS 不防 ABA:节点 A 被弹出、析构、新节点又恰好分配到同一地址,CAS 误判“还是原来的 A”,导致链表断裂或崩溃。
这不是 compare_exchange_weak 的 bug,而是裸指针 CAS 的固有缺陷。可行解法只有显式处理:
- 用带版本号的 tagged pointer:把指针低 2–4 位腾出来存递增计数,存进
std::atomic<uint64_t></uint64_t>,CAS 时一起比; - 用
std::shared_ptr配合 hazard pointer 或 epoch-based reclamation,靠引用计数延缓回收; - 不推荐用
std::atomic<:shared_ptr>></:shared_ptr>——C++11/14 不保证其原子性,C++20 才支持,且仍有 ABA 风险。
真正容易被忽略的是:expected 被更新这件事不是“副作用”,而是你维持循环正确性的核心机制——它让你不用额外 load,就能拿到最新值。一旦把它当成普通入参忽略,整个无锁逻辑就垮了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











