compare_exchange_weak 更适合自旋锁,因其允许虚假失败、生成更轻量指令,配合循环重试可降低开销;必须在循环中用返回值判断成功与否,且需重置 expected 值,搭配 acquire/release 内存序即可。

compare_exchange_weak 为什么比 compare_exchange_strong 更适合自旋锁
因为 compare_exchange_weak 允许虚假失败(spurious failure),在某些架构(如 ARM、旧版 x86)上能生成更轻量的指令序列,循环中重试成本更低。而自旋锁本就预期在冲突少时快速成功、冲突多时反复尝试,虚假失败不影响逻辑正确性,反而避免了 compare_exchange_strong 可能引入的额外内存屏障或 cmpxchg 指令开销。
常见错误是把它当“弱版强保证”用——比如在非循环场景下没检查返回值就继续执行,结果逻辑跳过关键判断。
- 必须在 do-while 或 while 循环中使用,靠返回值驱动重试
- 不能只依赖
expected值不变就认为成功;必须用返回值(bool)判断是否真正交换成功 -
expected参数必须是变量(非常量左值),因为失败时它会被原子地更新为当前实际值
手写自旋锁:std::atomic_flag vs std::atomic vs std::atomic
最简且推荐的方式是用 std::atomic_flag(无锁、lock-free、专为锁设计),但若要用 compare_exchange_weak,就得选整型或布尔型 std::atomic。注意:std::atomic<bool></bool> 在部分平台可能不是 lock-free,而 std::atomic<int></int> 通常更可靠。
典型错误是用 std::atomic<bool></bool> 并设初值为 false 表示“未锁定”,却在 compare_exchange_weak 中传入 true 作 expected ——这会直接失败,因为初始值不匹配。
- 约定:0 表示“空闲”,1 表示“已锁定”(用
int避免布尔特化陷阱) - 获取锁时,期望值为 0,新值为 1;成功则获得锁,失败则更新
expected为当前值(可能是 1),继续循环 - 释放锁只需
store(0, std::memory_order_release),无需原子操作
内存序怎么选:memory_order_acquire/release 足够,别乱用 sequential_consistent
自旋锁只要保证临界区前后内存访问不被重排即可。compare_exchange_weak 成功时需 acquire 语义(进入临界区前),失败时不产生副作用;解锁用 release 语义(退出临界区后)。用 std::memory_order_seq_cst 会拖慢性能,尤其在多核 NUMA 系统上。
容易踩的坑是把 acquire 放在失败分支里,或者对失败路径也加 memory_order_acq_rel ——失败时没有修改共享状态,不需要任何内存序约束。
- 成功获取锁:用
compare_exchange_weak(..., std::memory_order_acquire) - 释放锁:用
store(0, std::memory_order_release) - 失败重试:无需指定内存序(默认
std::memory_order_seq_cst仅用于成功路径)
一个可运行的 minimal 自旋锁实现
struct spinlock {
std::atomic<int> flag{0};
void lock() {
int expected = 0;
while (!flag.compare_exchange_weak(expected, 1, std::memory_order_acquire)) {
expected = 0; // 重置期望值,因失败时 expected 已被更新为当前值(即 1)
// 可选:_mm_pause() 或 std::this_thread::yield() 减少忙等开销
}
}
void unlock() {
flag.store(0, std::memory_order_release);
}
};
</int>
注意 expected = 0 这一行:如果不重置,下次循环传入的是 1,compare_exchange_weak 就永远失败。这是初学者最常漏掉的点。
真实场景中还要考虑中断安全、优先级反转、以及是否值得用自旋锁——如果临界区长于几个微秒,不如用 mutex。spinlock 只适合极短、确定的临界区。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











