std::atomic 比 mutex + condition_variable 更轻量,因其底层通常编译为单条 cpu 指令,无系统调用和内核态切换;而 condition_variable 需线程挂起/唤醒,开销高一个数量级。

std::atomic 为什么比 mutex + condition_variable 更轻量?
因为 std::atomic<bool></bool> 底层通常编译为单条 CPU 指令(如 x86 的 lock xchg 或 mov + 内存屏障),不涉及系统调用、内核态切换或等待队列管理。而 std::condition_variable 必须配合 std::mutex 使用,每次通知/等待都可能触发线程挂起/唤醒,开销高一个数量级。
但它只适合「单次通知」或「状态轮询」场景——不能像条件变量那样携带 payload、无法阻塞等待「直到某条件成立」,也不能广播或重置通知状态(除非手动干预)。
如何避免 std::atomic<bool></bool> 的 ABA 和忙等陷阱?
常见错误是写成 while 循环持续读取:while (!flag.load()) { /* 空转 */ },这会吃满 CPU 核心,且在低优先级线程中可能延迟响应。
- 用
std::this_thread::yield()让出时间片:while (!flag.load(std::memory_order_acquire)) { std::this_thread::yield(); } - 更推荐用
std::this_thread::sleep_for()配合指数退避(仅适用于对延迟不敏感的场景) -
std::atomic<bool></bool>本身不涉及 ABA 问题(只有 true/false 两个值),但若你用它模拟多状态(比如用true表示“就绪”,false表示“未就绪”再加额外状态字段),就要注意状态耦合——此时应改用std::atomic<int></int>或std::atomic_flag
notify_one() 风格的单次通知怎么写才安全?
典型模式是:生产者写 flag.store(true, std::memory_order_release),消费者读 flag.load(std::memory_order_acquire)。关键在内存序配对——release 写保证其前所有内存操作对 acquire 读可见。
但要注意:一旦消费者读到 true,flag 就处于“已通知”状态;如果消费者没做清理,后续循环还会立即进入。所以单次通知必须配合手动重置:
std::atomic<bool> ready{false};
<p>// 生产者
data = 42; // 准备数据
ready.store(true, std::memory_order_release); // 发送通知</p>
<p>// 消费者
while (!ready.load(std::memory_order_acquire)) {
std::this_thread::yield();
}
// 此时 data 已就绪
use(data);
ready.store(false, std::memory_order_relaxed); // 重置,供下次使用</p></bool>
重置用 relaxed 即可——因为此时没有其他线程依赖这个写操作的同步语义。
std::atomic_flag 和 std::atomic 选哪个?
std::atomic_flag 是 C++ 中唯一保证无锁(lock-free)的原子类型,且默认初始化为 clear(即 false),语义更贴近「通知旗标」。而 std::atomic<bool></bool> 在某些平台(如旧 ARM)可能被实现为带锁的封装,导致意外性能回退。
如果你只需要「设旗 → 查旗 → 清旗」三步,且不关心初始值是否可设为 true,优先用 std::atomic_flag:
std::atomic_flag ready = ATOMIC_FLAG_INIT;
<p>// 通知(原子 set)
ready.test_and_set(std::memory_order_release);</p><p>// 等待(自旋)
while (ready.test(std::memory_order_acquire)) {
std::this_thread::yield();
}</p><p>// 注意:atomic_flag 没有直接的 clear 方法,需用 test_and_set(false)
ready.clear(std::memory_order_relaxed);</p>
真正容易被忽略的是:不同平台对 std::atomic<bool></bool> 是否 lock-free 没有强制要求,运行时可用 flag.is_lock_free() 或 bool.is_lock_free() 检查——别只看文档,实测才是关键。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











