std::atomic的wait/notify机制提供无锁、低延迟的线程通知,支持bool单次事件与int计数器多事件场景,需配合循环检查、正确内存序及类型限制使用,相比condition_variable避免锁争用与通知丢失。

如果您在C++多线程编程中需要实现轻量级、无锁的线程间事件通知机制,则std::atomic的wait/notify接口可替代传统条件变量以降低唤醒延迟与系统调用开销。以下是针对该机制的原理剖析与具体使用方式:
一、理解 std::atomic::wait 与 notify 的底层语义
std::atomic
1、确保所用原子类型支持等待操作:仅 std::atomic
2、调用 wait 前必须保证原子变量处于期望值,否则函数立即返回;不会自动重试或轮询其他值。
立即学习“C++免费学习笔记(深入)”;
3、notify_one 仅唤醒一个正在 wait 且预期值匹配的线程,notify_all 唤醒所有匹配等待者;未处于 wait 状态的线程不会被影响,亦无“丢失通知”风险。
二、基于 std::atomic 实现单次事件触发
适用于“信号一次即生效”的场景,例如初始化完成、任务终止标志、中断请求等。利用 bool 类型的简洁性与 wait/notify 的低延迟特性,避免引入 mutex。
1、声明全局或共享的 std::atomic
2、等待方调用 var.wait(false),使线程挂起直至变量变为 true;传入 false 表示“等待它变成 true”。
3、通知方执行 var.store(true, std::memory_order_release) 后立即调用 var.notify_one();store 与 notify 顺序不可颠倒,否则可能造成唤醒遗漏。
三、使用 std::atomic<:uint64_t> 实现计数器式多事件通知
通过整型原子变量模拟轻量信号量,支持多次 notify 并累积状态,适用于生产者-消费者模型中的就绪项计数,或批量任务完成通报。
1、定义 std::atomic<:uint64_t> counter{0};初始值必须为 0,否则 wait 可能永不返回。
2、等待方执行 while (counter.load(std::memory_order_acquire) == 0) { counter.wait(0); },形成带等待的忙等循环;每次 wait 失败后需重新 load 判断,防止虚假唤醒。
3、通知方执行 counter.fetch_add(1, std::memory_order_acq_rel) 后调用 counter.notify_one();fetch_add 返回旧值,若为 0 则说明有线程正等待,notify_one 必须紧随其后。
四、规避虚假唤醒与内存序误用的典型错误
wait/notify 不提供内置的谓词重检查机制,因此用户必须手动处理虚假唤醒,并严格约束内存序以保障可见性。
1、永远不要在无循环包裹下直接调用 wait;必须配合 load 判断构成 while 循环,否则可能跳过已发生的通知。
2、wait 内部隐含 acquire 语义,但 store/notify 组合中 store 必须使用 release 或更强序;使用 memory_order_relaxed 的 store 后 notify 无法保证等待线程看到此前的内存修改。
3、禁止跨线程复用同一原子变量承载不同语义;例如既用作 ready 标志又用作 error code,将导致 wait 条件逻辑混乱。
五、与 std::condition_variable 的关键行为差异验证
在相同线程数量与通知频率下,wait/notify 的上下文切换次数更少,尤其在高竞争低唤醒率场景中体现明显,因其可跳过用户态到内核态的完整条件变量路径。
1、std::condition_variable::wait 要求持有 std::unique_lock,必然引发 mutex 争用;而 atomic::wait 完全不涉及任何锁对象或 RAII 管理。
2、condition_variable 通知丢失风险存在于 notify 在 wait 之前发生的情形;atomic::notify 对已 past 的 wait 无作用,但 wait 本身不依赖“通知历史”,只依赖当前值,故无此问题。
3、std::atomic


















