c++oding="utf-8" ?>
std::atomic::wait 是 c++20 引入的平台相关原子等待机制,仅在支持 futex/srwlock 等内核原语的系统上可用,需编译器(gcc 11+/clang 12+/msvc 17.5+)启用 c++20 及对应扩展,且仅整型特化支持;必须配合 notify_one/notify_all 使用,仅支持精确值匹配,需循环检查并确保内存序兼容(推荐 seq_cst),否则可能忙等或失效。

std::atomic::wait 是 C++20 新增的等待机制,不是所有编译器默认启用
它只在支持 std::atomic 的“带等待/通知语义”的平台(如 Linux futex、Windows SRWLock)上可用,且要求编译器开启 C++20 并启用对应扩展。GCC 11+、Clang 12+、MSVC 2022 17.5+ 支持,但 GCC 默认不启用 __cpp_lib_atomic_wait 宏——你得手动加 -latomic(某些旧版 GCC)或确认标准库实现已启用该特性。
常见错误现象:error: 'wait' is not a member of 'std::atomic',本质是标准库头文件没暴露该接口,或编译选项未对齐 C++20。
- 检查是否定义了
__cpp_lib_atomic_wait:在代码开头加#ifdef __cpp_lib_atomic_wait防止编译失败 - Clang 需要
-std=c++20 -D_LIBCPP_ENABLE_CXX20_ATOMIC_WAIT(若用 libc++) - MSVC 无需额外宏,但必须用 /std:c++20 且更新到较新工具集
- 注意:
std::atomic<bool></bool>、std::atomic<int></int>等整型特化才支持wait;std::atomic<t></t>不支持(指针类型无 wait 成员)
wait 必须配合 notify_one/notify_all 使用,且只能等值变化
std::atomic::wait 不是条件变量,它只在当前原子值等于传入的 expected 时挂起线程,一旦其他线程调用 notify_one 或 notify_all,它就立即唤醒并重新检查值是否仍为 expected(spurious wakeup 可能发生,需循环判断)。
它不能替代 std::condition_variable 去等待任意布尔逻辑(比如 “sum > 100”),只能用于“某个原子变量恰好等于某值”这种精确匹配场景。
- 典型用法是“等待 flag 变成 true”:
flag.wait(false);,然后另一线程执行flag.store(true); flag.notify_all(); - 必须用循环包裹:
while (a.load() == expected) a.wait(expected);,否则可能错过通知或被虚假唤醒 -
notify_one只唤醒一个等待线程;notify_all唤醒全部——但被唤醒的线程仍要重新比对值,不保证一定“抢到” - 不要在持有锁期间调用
wait,它内部会释放并重获底层等待原语,与互斥锁无关
wait 和 load/store 的内存序必须兼容
std::atomic::wait 内部隐式使用 memory_order_acquire 语义读取当前值,因此你调用 wait(expected) 时,传入的 expected 应该是通过至少 acquire(或更强)序读取的值,否则可能因重排导致等待永远不触发。
换句话说:如果另一个线程用 store(new_val, std::memory_order_relaxed) 更新了原子变量,而你用 wait(old_val) 等待,很可能等不到——因为 relaxed store 不同步到等待线程的 view。
- 安全做法:所有涉及
wait/notify的读写都统一用std::memory_order_seq_cst(默认),或至少写端用release、读端用acquire -
notify_one和notify_all自动带有memory_order_release效果,确保之前的所有写操作对被唤醒线程可见 - 避免混合 relaxed 操作:比如用
load(relaxed)得到expected,再传给wait(),这是危险的
wait 在非多核系统或调试模式下可能退化为忙等
部分标准库实现(尤其是未优化的 libc++ 或老版本 libstdc++)在检测不到内核等待原语支持时,会 fallback 到自旋 + yield,导致 CPU 占用率飙升。这不是 bug,而是规范允许的降级行为。
实际部署前务必在目标环境中验证:运行一个长时间 wait 的线程,观察 top 或 perf 是否显示持续占用一个核。
- Linux 上可通过
strace -e futex确认是否真正进入内核等待 - macOS 不支持 futex,libc++ 使用 pthread_cond_t 模拟,性能略低但不会忙等
- Windows 上依赖
WaitOnAddress,需 Windows 8+,否则同样 fallback - 单元测试中若想避免等待,可改用
std::this_thread::yield()+ 轮询模拟,但生产环境别这么干
std::atomic::wait 看似简单,但它的正确性高度依赖平台支持、内存序一致性和使用边界——漏掉任何一个,就容易卡死、忙等或根本收不到通知。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











