std::atomic::wait仅支持整型特化(如std::atomic<int>、std::atomic<bool>)及平台原语支持的平凡可复制类型,因底层依赖futex/WaitOnAddress等内核机制,且要求类型满足sizeof(T)≤指针宽度、lock-free、trivially copyable;std::atomic<std::string>等不满足条件的类型无wait成员,编译失败。

std::atomic::wait 为什么不能直接用在所有原子类型上
因为 std::atomic::wait 只对 std::atomic<bool></bool>、std::atomic<:shared_ptr>></:shared_ptr> 和整型特化(如 std::atomic<int></int>、std::atomic<long></long> 等)有定义,且要求底层平台支持等待/通知原语(如 Linux futex、Windows WaitOnAddress)。不是所有 std::atomic<t></t> 都能调用 wait —— 比如 std::atomic<:string></:string> 或自定义结构体,编译会直接报错:no member named 'wait'。
常见误操作是把普通 std::atomic<int></int> 声明成 const 或绑定到 const auto&,导致无法调用非 const 成员函数 wait;也有人忽略头文件依赖,没加 #include <atomic> 或 #include <thread>(后者在某些标准库实现中影响等待函数可见性)。
如何正确触发 std::atomic::notify_one / notify_all
notify_one 和 notify_all 必须由**修改原子变量值的线程**在写操作后显式调用,且写操作与通知之间不能有重排(编译器或 CPU 层面)。否则等待线程可能永远收不到信号。
- 推荐写法:用
store(new_val, std::memory_order_release)+notify_one(),确保 store 的内存序足够强 - 避免写法:
a = new_val; a.notify_one();—— 这里赋值默认是seq_cst,但编译器仍可能重排 notify(实际少见,但不保证) - 更安全的惯用写法是封装成函数:
void set_and_notify(std::atomic<int>& a, int val) { a.store(val, std::memory_order_release); a.notify_one(); }
wait 的超时与虚假唤醒怎么处理
std::atomic::wait 本身不支持超时,必须配合 std::atomic::wait_until 或 std::atomic::wait_for。但要注意:这些函数返回后,**必须重新检查条件是否真正满足**,因为存在虚假唤醒(spurious wakeup)—— 即没被 notify 也返回了。
立即学习“C++免费学习笔记(深入)”;
典型错误是写成:
flag.wait(false); // 错!假设 wait 返回就代表 flag 变成了 true do_work();
正确做法是循环检查:
while (flag.load() == false) {
flag.wait(false);
}
do_work();
如果需要带超时:
auto tp = std::chrono::steady_clock::now() + 100ms;
while (flag.load() == false && std::atomic_wait_until(&flag, false, tp)) {
// 注意:wait_until 返回 true 表示被 notify,false 表示超时
// 但即便返回 true,仍需 reload 检查值
}
if (flag.load()) {
do_work();
}
Linux 下性能差异:futex vs 自旋+yield
当原子变量处于等待状态时,std::atomic::wait 在 Linux 上会陷入内核调用 futex(FUTEX_WAIT),线程进入休眠,不消耗 CPU;而手写 while-loop + std::this_thread::yield() 会持续占用一个核心,延迟更低但浪费资源。
但注意:futex 有开销 —— 每次 notify 需要一次系统调用,频繁通知(比如每微秒一次)反而比自旋慢。所以高频短等待场景(如 lock-free queue 的 producer-consumer 微同步),wait 不一定更优。
验证是否真走 futex:用 strace -e trace=futex 运行程序,能看到大量 futex(... FUTEX_WAIT ...) 调用;若没看到,说明编译器回退到了用户态忙等(通常是平台不支持或原子类型不满足条件)。
容易被忽略的一点:std::atomic::wait 要求等待值与当前值严格相等才挂起,哪怕只差一个 bit(比如 int 的符号位),也会立即返回而非等待 —— 这和条件变量的语义不同,别想当然当成“等待变为 true”。



















