sleep_for/sleep_until不释放锁,仅暂停当前线程;wait需配合mutex和条件变量,自动释放并重获锁;yield不休眠、不释放锁、不可替代wait。

sleep_for / sleep_until 不释放锁,也不需要同步上下文
在 C++11 及之后的标准库中,std::this_thread::sleep_for 和 std::this_thread::sleep_until 是线程休眠的正规方式。它们只影响当前线程的调度状态,不涉及任何对象锁——无论你是否在 std::mutex 保护的临界区里调用,锁都始终持有。
这意味着:如果你在 std::lock_guard 或 std::unique_lock 作用域内调用 sleep_for,其他线程会一直阻塞等待该锁释放,直到休眠结束。这不是 bug,而是设计如此:它只是“暂停执行”,不是“让出协作权”。
- 可在任意位置调用,无需
synchronized(C++ 没这关键字)或lock前置条件 - 不抛出异常,但可能被中断(需配合
std::jthread或手动检查std::this_thread::interrupted()) - 精度受系统调度器限制,
sleep_for(1ms)实际可能延迟 10–15ms
wait 需要条件变量 + 互斥锁,本质是“等某个条件成立”
C++ 中没有叫 wait() 的孤立函数;真正用于线程等待的是 std::condition_variable::wait,它必须和 std::mutex 配套使用。它的行为和 Java 的 Object.wait() 更接近:调用时自动释放传入的互斥锁,并挂起线程;被唤醒后重新尝试获取该锁,再返回。
关键点在于:它不是“睡一会儿”,而是“等一个信号”。这个信号通常由另一个线程通过 notify_one() 或 notify_all() 发出,且往往对应某个共享状态的变化(比如队列非空、任务完成、标志位为 true)。
立即学习“C++免费学习笔记(深入)”;
- 必须传入已锁定的
std::unique_lock<:mutex></:mutex>,否则触发std::system_error - 存在虚假唤醒(spurious wakeup),所以必须配合 while 循环检查条件,不能用 if
-
wait(lock, pred)形式是推荐写法,内部自动处理循环和重锁逻辑
别把 std::this_thread::yield() 当 wait 用
std::this_thread::yield() 常被误认为是轻量版 wait,但它只是建议调度器“换一个线程运行”,不休眠、不等待、不释放锁、也不保证切换发生。它既不会让出互斥锁,也不会阻塞,更无法替代条件变量的协作语义。
典型误用场景:想让生产者等消费者处理完再继续,却只写 yield() ——结果是忙等(busy-wait),CPU 占用飙高,逻辑还不可靠。
- yield 后线程状态仍是
runnable,随时可能被再次调度 - 没有内存序语义,不保证对共享变量的可见性,不能替代锁或 condition_variable
- 仅适合极短等待、且能容忍不确定性的场景(如自旋锁退避)
容易踩的坑:混用 sleep 和 condition_variable
最常见错误是试图用 sleep_for 替代 condition_variable::wait 来实现线程间协调。例如:消费者循环检查队列是否为空,为空就 sleep_for(10ms)。这会导致三个问题:
- 忙等浪费 CPU,尤其当休眠时间很短时
- 唤醒不及时:即使生产者刚 push 完,消费者也要再等最多 10ms 才发现
- 竞争条件:两次检查之间队列状态可能已变,但无锁保护下读取可能不一致
真正安全的做法是用 std::condition_variable 配合 std::mutex,让等待变成“被通知即响应”,而不是“轮询+硬等”。sleep 系列只适用于“我就是想停几毫秒”,不是“我在等别人告诉我可以继续了”。


















