必须用 compare_exchange_strong 的场景是需严格区分“值已改变”和“纯硬件失败”时,如无锁队列 pop、状态机单次跃迁、调试关键路径等;它保证值相等必成功,避免 weak 的虚假失败破坏一致性。

compare_exchange_strong 不是“更安全的 compare_exchange_weak”,而是语义不同的工具——它保证“值相等就一定成功”,适合非循环、单次尝试必须明确区分失败原因的场景。
什么时候必须用 compare_exchange_strong?
核心判断点:你是否需要严格区分“值已改变”和“纯硬件失败”。
- 实现无锁队列的
pop操作时,若compare_exchange_weak在值未变时虚假失败,会导致本该成功的出队被跳过,破坏数据一致性 - 状态机中只允许一次跃迁(如从
INIT→READY),不允许因虚假失败重试而绕过中间校验逻辑 - 调试或日志关键路径,要求每次失败都对应真实的数据竞争,而非底层 LL/SC 指令的偶然抖动
compare_exchange_weak 循环里硬换 strong 会怎样?
多数情况下不会报错,但可能悄悄拖慢性能,尤其在 ARM/AArch64 上。
-
compare_exchange_strong在弱模型平台常通过内部隐式重试实现,等价于手写 do-while + weak —— 你写了循环,它又套了一层循环 - x86 上差异小(几乎无虚假失败),但代码可移植性下降;ARM 上可能多执行 2–3 次内存检查,增加 cache line bouncing
- 如果 failure 内存序设得太强(比如
std::memory_order_acquire),而 success 只用relaxed,编译器可能拒绝编译(违反failure ≤ success规则)
参数传错 expected 引用会崩溃吗?
不会崩溃,但行为完全失控——expected 必须是可修改的左值引用,否则编译失败。
立即学习“C++免费学习笔记(深入)”;
- 常见错误:
long expected = 0;然后传counter.compare_exchange_strong(expected, 1)✅ 正确 - 错误写法:
counter.compare_exchange_strong(0L, 1)❌ 编译不过:字面量不能绑定到非 const 引用 - 更隐蔽的坑:
const long exp = 0;传exp也会编译失败;若误用指针解引(如*p但p为 null),运行时崩溃 - CAS 失败时,
expected会被自动更新为当前原子值——这是唯一能拿到最新快照的方式,别忽略它
为什么 memory_order 选错比函数选错更危险?
因为错误不报错、不崩溃,只让并发逻辑在特定负载下间歇性失效。
- 用
std::memory_order_relaxed做 flag + data 协同更新:data 修改对其他线程不可见,哪怕 CAS 成功 - 读端没配
acquire,写端用了release,happens-before 关系断裂,导致看到“半初始化”的结构体字段 - 初学者最稳妥起点是
std::memory_order_acq_rel(对 CAS 本身),它同时提供 acquire 读屏障和 release 写屏障,覆盖大多数 flag+payload 场景
真正难的不是记住哪个函数叫什么,而是每次写 CAS 时,都得问自己一句:我这次操作,到底是在同步一个值,还是在同步一组相关内存?后者永远比前者多一层责任。


















