compare_exchange_strong并非总是失败,而是需配合循环重试:因其他线程可能抢先修改值,失败时会将当前实际值写回expected,故expected必须为可修改左值且在循环中持续更新。

compare_exchange_strong 为什么总是失败?
它不是“总是失败”,而是设计上必须配合循环重试——因为底层可能被其他线程抢先修改了值。你写成 if (flag.compare_exchange_strong(expected, desired)) 却没进分支,大概率是 expected 在调用前就被别的线程改过,而 compare_exchange_strong 检查失败后会把当前实际值写回 expected,但你没再读一次就继续用了。
- 必须用 do-while 或 while 循环包裹,典型模式是:先读当前值到
expected,再尝试交换,失败就用新值重试 -
expected必须是可修改的左值(不能是字面量或临时量),否则编译报错:error: binding reference of type 'int&' to 'int' discards qualifiers - 返回
false时,expected已被更新为内存中最新值,这是它和compare_exchange_weak的关键区别之一
怎么写一个安全的原子计数器自增?
直接 ++counter 是原子的,但如果你想在自增的同时做条件判断(比如“只在小于100时加1”),就必须用 compare_exchange_strong。
std::atomic<int> counter{0};
int expected = counter.load();
do {
if (expected >= 100) break;
} while (!counter.compare_exchange_strong(expected, expected + 1));</int>
-
load()获取初始值,避免在循环外用counter直接赋值导致竞态 - 循环体内先做业务逻辑判断(如
expected >= 100),再调用compare_exchange_strong,失败后expected自动更新,下次迭代用新值继续判 - 注意:如果业务逻辑复杂、耗时长,要考虑是否该用锁,否则可能引发大量重试和 CPU 空转
compare_exchange_strong 和 weak 选哪个?
绝大多数场景用 compare_exchange_strong 更稳妥;只有在明确知道目标平台(如 x86)下不会因伪失败重试,且性能极度敏感时,才考虑 weak 版本。
-
strong保证:只要内存值没变,就一定成功;weak允许“伪失败”(spurious failure),即值没变也返回false,必须靠循环兜底 - ARM 或某些弱一致性架构上,
weak可能生成更轻量指令,但现代编译器对strong优化已很好,差异通常可忽略 - 初学者一律用
strong,别为了省几个 cycle 引入难以复现的并发 bug
bool 类型的 compare_exchange_strong 容易踩什么坑?
常见错误是把 expected 声明为 const bool 或字面量 true/false,导致编译不过。
- 正确写法:
bool expected = flag.load();,然后传expected(非 const 引用) - 如果想实现“首次设置为 true 并返回是否成功”,代码是:
bool expected = false; flag.compare_exchange_strong(expected, true); - 注意:
compare_exchange_strong对bool的语义是“如果当前是expected,就设成desired”,不是“如果为 false 就设 true”——所以expected必须反映你期望的旧值
expected 的可变性、类型匹配——这三个点卡住的人最多。写的时候盯着这三处检查一遍,基本不会掉进原子操作的坑里。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











