std::atomic::exchange 不会阻塞线程,它是无锁的原子操作,底层通常编译为单条cpu指令;但是否真正lock-free取决于类型和平台,需通过is_always_lock_free或is_lock_free检查。

std::atomic::exchange 会阻塞线程吗?
不会。std::atomic::exchange 是一个无锁(lock-free)操作,底层通常编译为单条 CPU 指令(如 x86 的 xchg 或 lock xchg),不涉及互斥量或系统调用,因此不会引起线程阻塞或上下文切换。
但要注意:是否真正 lock-free 取决于类型和平台。可通过 T::is_always_lock_free(C++17 起)或 std::atomic<t>::is_lock_free()</t> 运行时检查。例如 std::atomic<:shared_ptr>></:shared_ptr> 在某些平台上就不是 lock-free 的。
- 对
int、long、指针等基础尺寸类型,主流编译器+硬件下基本都保证 lock-free - 对自定义结构体,即使只有两个
int成员,也可能 fallback 到内部 mutex 实现,此时exchange会隐式加锁——但行为仍是原子的,只是性能下降 - 若不确定,用
static_assert(std::atomic<int>::is_always_lock_free, "")</int>编译期断言更稳妥
exchange 和 load/store + compare_exchange_weak 有什么本质区别?
exchange 是“读-改-写”一步完成:它返回旧值,同时将变量设为新值,整个过程不可分割。而 load + store 是两步,中间可能被其他线程干扰;compare_exchange_weak 则需要循环重试,适用于“读-判断-有条件写”的场景。
典型误用:有人想用 compare_exchange_weak 实现无条件替换,结果写出死循环或漏更新:
auto old = atomic_var.load();
while (!atomic_var.compare_exchange_weak(old, desired)) {
// 如果别的线程已改过值,old 被自动更新,但逻辑里没重算 desired...
}
-
exchange更简洁、更高效,适合“我只关心旧值,且必须替换成这个新值”的场景(如清零计数器、交换状态标志、实现简易无锁栈头) -
compare_exchange_weak适合“仅当满足某条件才替换”,比如引用计数递减后检查是否归零 - 性能上,
exchange通常比 CAS 循环快——没有分支预测失败开销,也没有重试成本
如何正确使用 memory_order 参数?
exchange 默认使用 std::memory_order_seq_cst(顺序一致性),这是最安全也最重的内存序。多数情况下够用,但若明确知道上下文不需要强同步,可降级以提升性能。
- 如果只是替换一个独立的状态标志(如
std::atomic<bool> ready</bool>),且其他线程只通过该标志做简单判断,用std::memory_order_acq_rel即可 - 若新值完全不依赖其他内存位置,且旧值也不用于后续依赖读取,甚至可用
std::memory_order_relaxed(但极少这么用,容易出错) - 切忌混用:比如一个线程用
acq_rel,另一个线程对同一变量用relaxedstore,可能破坏期望的同步语义 - 调试时可先全用
seq_cst,压测发现瓶颈后再逐个分析降级
常见错误:把 exchange 当作 fetch_add 或 swap
exchange 不是加法,也不是双向交换。它总是把原子变量**设为给定值**,并返回**替换前的值**。新手常混淆它与 fetch_add(返回旧值并加)或 std::swap(双向赋值)。
例如想实现“原子地加 1 并获取新值”,错误写法:
int new_val = counter.exchange(counter.load() + 1); // 错!中间有竞态
正确做法是用 fetch_add(1) 或 exchange 配合循环(不推荐)。
-
exchange的参数是“要设成的值”,不是“要加的值” - 它不检查当前值,不比较,不条件执行——就是强制覆盖
- 若需“读取后处理再写回”,必须用
compare_exchange_weak循环,或选对对应原子运算(fetch_or、fetch_sub等)
真正适合 exchange 的场景其实很明确:你手头有一个确定的新值,且必须原子地把它放进去,同时需要知道原来是什么——比如释放资源前读取句柄、切换状态机状态、归还对象到对象池。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











