std::atomic::exchange不是简单赋值,因为它是原子的“读-改-写”操作,返回旧值并写入新值,全程不可打断;普通赋值仅写入且非原子,无法保证线程安全。

std::atomic::exchange 为什么不是简单的赋值
因为 exchange 是原子的“读-改-写”操作:它返回旧值的同时把新值写入,整个过程不可被其他线程打断。普通赋值(var = new_val)只写不读,且非原子;而 exchange 天然适合实现锁-free 的状态切换、资源移交或标志位翻转。
基本用法和参数类型必须严格匹配
调用 exchange 时传入的新值类型必须与原子对象的模板类型一致,否则编译失败。例如 std::atomic<int></int> 不能用 exchange(3.14),也不能隐式转换成 long 后传入。
- 支持的参数是右值或可移动/可拷贝的左值,但推荐直接传字面量或变量(如
a.exchange(1)) - 第二个可选参数
memory_order默认为std::memory_order_seq_cst,若需性能优化可显式指定(如std::memory_order_relaxed),但要清楚弱序下对其他变量的可见性不保证 - 返回值是操作前的旧值,类型与原子类型相同,可直接用于判断或后续逻辑
典型场景:实现自旋锁或状态机切换
比如用 std::atomic<bool></bool> 实现一个简单自旋锁:
std::atomic<bool> locked{false};
void lock() {
while (locked.exchange(true, std::memory_order_acquire)) {
// 自旋等待,exchange 返回 true 表示原来已被锁住
}
}
void unlock() {
locked.store(false, std::memory_order_release);
}</bool>
注意这里用了 std::memory_order_acquire 和 std::memory_order_release 配对,确保临界区内的读写不会被重排到锁外。如果只用 std::memory_order_relaxed,可能引发数据竞争。
容易踩的坑:忘记检查返回值或误用 memory_order
常见错误包括:
- 调用
exchange后忽略返回值,导致无法知道原状态(比如想确认是否首次设置标志位) - 在需要同步语义的地方用了
std::memory_order_relaxed,结果其他线程看不到你刚写入的数据 - 对
std::atomic<t></t>使用exchange(nullptr)却没考虑指针生命周期,造成悬空指针 - 在非 trivially copyable 类型上使用
std::atomic(C++20 前不支持),编译报错std::atomic<myclass> is not a valid specialization</myclass>
真正难的不是调用 exchange 这一行代码,而是搞清它在内存模型中的位置——它不只是换了个值,还是一道同步栅栏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











