std::atomic_compare_exchange_weak/strong 是标准定义的底层自由函数,但日常应使用 std::atomic::compare_exchange_weak/strong 成员函数;不存在 std::atomic_compare_exchange_cxx。

直接说结论:std::atomic_compare_exchange_weak 和 std::atomic_compare_exchange_strong 是 C++ 原子 CAS 的实际入口函数,std::atomic::compare_exchange_weak/strong 成员函数才是日常该用的写法;裸调用自由函数版本几乎没理由 —— 它不自动推导内存序,且容易误传参数类型。
为什么不能直接用 std::atomic_compare_exchange_cxx 这种自由函数?
标准库中根本不存在叫 std::atomic_compare_exchange_cxx 的函数。你搜到的可能是拼写错误、过时资料,或把底层编译器内建函数(如 __atomic_compare_exchange_n)误当成了标准接口。C++ 标准只定义了两个自由函数:
std::atomic_compare_exchange_weakstd::atomic_compare_exchange_strong
但它们是为泛型算法设计的底层适配器,要求显式传入 std::atomic、期望值指针、期望值本身、期望更新值、以及两套内存序 —— 容易出错,且和 std::atomic 对象的常规使用习惯脱节。
compare_exchange_weak 和 compare_exchange_strong 怎么选?
两者语义一致:比较当前值是否等于 expected,是则替换为 desired 并返回 true;否则将当前值写回 expected 并返回 false。关键差异在「失败行为」:
立即学习“C++免费学习笔记(深入)”;
-
weak版本允许「伪失败」(spurious failure):即使值匹配,也可能返回false。常见于 LL/SC 架构(ARM、RISC-V),代价低、性能好 -
strong版本保证:只要值匹配,就一定成功。x86 上二者汇编等价;但 ARM 上strong可能重试多次,开销略高
实践建议:
典型用法与易错点
必须注意:第二个参数是引用,且函数会修改它。这是最常踩的坑 —— 忘记取地址或传值导致编译失败或逻辑错误。
std::atomiccounter{0}; int expected = 0; int desired = 1; // ✅ 正确:expected 是引用,会被更新 if (counter.compare_exchange_strong(expected, desired)) { // 成功:counter 从 0 → 1 } else { // 失败:expected 已被设为 counter 当前值(比如 1) // 此时 expected == 1,可继续用它重试 } // ❌ 错误:传值,expected 不会被更新,下次 compare_exchange 还拿旧值比 // int expected = 0; // counter.compare_exchange_strong(expected, desired); // 编译不过(类型不匹配) // ❌ 错误:取地址但没声明为引用,导致修改的是临时量 // counter.compare_exchange_strong(&expected, desired); // 编译不过(参数类型不对)
其他要点:
- 默认内存序是
std::memory_order_seq_cst,安全但有开销;高频场景可指定更弱的序,如compare_exchange_weak(expected, desired, std::memory_order_acquire, std::memory_order_relaxed) - 对
std::atomic或指针类型,expected类型必须严格匹配,不能隐式转换(例如不能用nullptr初始化int*引用) - 自定义类型 T 要求是 trivially copyable,且 sizeof(T) 通常需 ≤ 指针大小(否则可能降级为锁实现)
CAS 看似简单,但 expected 的生命周期、内存序搭配、weak/strong 的循环结构,三者稍有错位就会导致死循环、ABA 问题或数据竞争 —— 尤其在多核弱一致性架构上,别只盯着函数名,得盯住变量怎么传、谁改了它、改完之后你还信不信它。











