不会。std::atomic::exchange是无锁操作,底层通常编译为单条CPU指令(如x86的XCHG),不阻塞线程;仅当is_lock_free()为false时退化为内部加锁,才可能产生短暂等待。

std::atomic_exchange 会阻塞线程吗?
不会。它是一个无锁操作,底层通常编译为单条 CPU 指令(如 x86 的 XCHG 或 LOCK XCHG),不涉及系统调用或内核态切换,因此不会导致线程挂起或调度延迟。
但要注意:如果目标对象是 std::atomic<bool> 这类 trivially copyable 类型,std::atomic_exchange 行为明确;而对自定义类型(哪怕只是加了 std::atomic 包装)——只要其 is_lock_free() 返回 false,就会退化为内部互斥锁实现,此时虽仍保证原子性,但可能引发争用下的短暂等待。
- 用
obj.is_lock_free()在运行时确认是否真正无锁 - 编译期可查
std::atomic<T>::is_always_lock_free(C++17 起) - 避免对大结构体(如 >16 字节)直接套
std::atomic,多数平台不支持 lock-free
std::atomic_exchange 和 operator= 的区别在哪?
std::atomic_exchange 做的是「读-改-写」原子操作:返回旧值,同时写入新值;而 operator= 只是单纯赋值,不返回原值,且在多线程下不保证与其他线程的读/写操作有序。
典型误用场景:有人试图用 atomic_var = new_val 替代 std::atomic_exchange 来“获取旧值”,这完全得不到旧值,还可能因缺少内存序导致重排问题。
立即学习“C++免费学习笔记(深入)”;
-
std::atomic_exchange(&var, new_val)→ 返回旧值,内存序默认memory_order_seq_cst -
var.store(new_val)→ 不返回旧值,仅写入 -
var.exchange(new_val)(成员函数)→ 等价于自由函数,更常用
如何正确使用 memory_order 参数避免性能陷阱?
默认使用 memory_order_seq_cst 安全但最重,尤其在高竞争场景下会显著拖慢吞吐。若业务逻辑允许更宽松的顺序约束,应显式指定更轻量的内存序。
例如:一个标志位仅用于通知另一线程“数据已就绪”,且该标志本身不参与其他数据依赖链,可用 memory_order_release 写 + memory_order_acquire 读配合 exchange。
- 只关心值替换、不依赖前后其他内存访问 → 用
memory_order_relaxed - 需保证 exchange 前的写操作对其他线程可见 → 用
memory_order_release - 需保证 exchange 后能读到其他线程此前用
release写入的数据 → 用memory_order_acquire - 混用不同内存序时,务必验证数据流依赖,否则可能引发未定义行为
常见错误:对非 trivially copyable 类型调用 std::atomic_exchange
编译器不会阻止你写 std::atomic<std::string>::exchange(...),但它根本不能编译通过 —— 因为 std::string 不满足 trivially copyable,std::atomic 对其特化不存在。这类错误通常在模板实例化时报错,信息模糊(如 “no member named ‘exchange’”)。
真正能用 std::atomic_exchange 的只有整数、指针、以及满足 is_trivially_copyable_v<T> 且大小适配的 POD 类型(如 struct { int a; char b; })。
- 检查类型:用
static_assert(std::is_trivially_copyable_v<T>)编译期断言 - 确认大小:x86-64 下通常 ≤8 字节才大概率 lock-free;ARM64 对齐要求更严格
- 替代方案:对复杂对象,改用
std::shared_ptr原子操作,或配合std::mutex手动保护
std::atomic_exchange 的返回值本质是“抢到的那个旧值”——它不承诺唯一性,多个线程并发调用时,每个都拿到自己执行时刻的快照,这点和 CAS 的语义差异容易被忽略。


















