C++ condition_variable::wait_for 全网最透彻讲解(3 种场景+可运行代码模拟)
·
在多线程编程里,std::condition_variable::wait_for 是同步核心,但也是最容易踩坑的函数。
这篇文章用最直白逻辑 + 3 种完整可运行模拟代码,把它的执行流程彻底讲透,看完再也不会懵。
一、先记住核心规则(背会这一段就够)
进入 wait_for:
1. 立刻执行一次 lambda 条件
2. 条件成立 → 直接返回 true,不睡觉、不解锁
3. 条件不成立 → 自动解锁 mutex → 线程休眠等待
醒来(两种可能:notify / 超时):
1. 自动重新上锁 mutex
2. 再次执行 lambda 条件
3. 条件成立 → 返回 true
4. 条件不成立
→ 没超时 → 继续解锁、睡觉
→ 超时了 → 返回 false
一句话总结:
不满足条件,绝对不会返回 true;醒了必须再查一遍,防止虚假唤醒。
二、场景 1:一开始条件就满足
行为
- 不等待、不睡眠、不解锁
- 锁全程保持上锁
- 直接返回
true
模拟代码
#include <iostream>
#include <mutex>
#include <condition_variable>
using namespace std;
int main() {
mutex mtx;
condition_variable cv;
int available = 2; // 一开始就满足条件
unique_lock<mutex> lock(mtx);
// 直接满足,不进入等待
bool ok = cv.wait_for(lock, chrono::milliseconds(5000), [&]() {
return available > 0;
});
cout << "ok: " << boolalpha << ok << endl; // true
cout << "锁一直保持上锁状态,没有被释放" << endl;
return 0;
}
输出
ok: true
锁一直保持上锁状态,没有被释放
三、场景 2:初始不满足 → 等待中被 notify → 最终满足
行为
- 初始条件不满足
- 自动解锁 → 线程休眠
- 其他线程修改条件 +
notify_one() - 本线程被唤醒 → 自动加锁
- 再次检查 lambda → 满足
- 返回
true
模拟代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
int main() {
mutex mtx;
condition_variable cv;
int available = 0; // 一开始不满足
// 子线程 2 秒后“释放资源”并通知
thread t([&]() {
this_thread::sleep_for(chrono::seconds(2));
lock_guard<mutex> lock(mtx);
available = 1; // 让条件满足
cv.notify_one(); // 唤醒等待线程
});
unique_lock<mutex> lock(mtx);
bool ok = cv.wait_for(lock, chrono::milliseconds(5000), [&]() {
return available > 0;
});
cout << "ok: " << boolalpha << ok << endl; // true
t.join();
return 0;
}
输出
ok: true
四、场景 3:初始不满足 → 超时也无人唤醒
行为
- 初始条件不满足
- 解锁 → 休眠
- 超时时间到,强制唤醒
- 再次检查 lambda → 仍然不满足
- 返回
false
模拟代码
#include <iostream>
#include <mutex>
#include <condition_variable>
using namespace std;
int main() {
mutex mtx;
condition_variable cv;
int available = 0; // 始终不满足
unique_lock<mutex> lock(mtx);
// 等待 3 秒,无人 notify
bool ok = cv.wait_for(lock, chrono::milliseconds(3000), [&]() {
return available > 0;
});
cout << "ok: " << boolalpha << ok << endl; // false
return 0;
}
输出
ok: false
五、最容易误解的重点(必看)
1. 被 notify 唤醒后,还会再查 lambda 吗?
会!一定会!
哪怕被唤醒,只要条件不满足,线程会继续睡觉,直到超时。
2. 超时唤醒后,还会查 lambda 吗?
会!
超时只是“不再等了”,不是“条件满足了”。
3. 什么时候锁会被释放?
只有条件不成立、进入等待时,才会自动解锁。
条件一开始就成立时,锁全程不释放。
4. 为什么要设计“醒来再检查”?
为了避免虚假唤醒(spurious wakeup):
操作系统可能在没有任何人 notify 的情况下,莫名其妙唤醒你。
必须再查一遍条件,才能保证逻辑安全。
六、终极判断表(一眼看懂)
| 场景 | 初始 lambda | 醒来方式 | 醒来 lambda | 结果 |
|---|---|---|---|---|
| 场景1 | true | 不等待 | - | true |
| 场景2 | false | notify | true | true |
| 场景3 | false | 超时 | false | false |
| 异常唤醒 | false | 虚假唤醒 | false | 继续睡 |
七、回到你的对象池代码
bool has_item = cv_.wait_for(lock, std::chrono::milliseconds(timeout_ms), [this]() {
return available_ > 0;
});
- 一开始池子满 → 直接过
- 池子空 → 睡觉
- 有人 release + notify → 醒来检查
- 检查满足 → 拿到资源
- 一直没人放 → 超时返回 false
逻辑完全严谨、无坑、工业级可用。
需要我再帮你加一段**“虚假唤醒模拟代码”**,让这篇博客更硬核、更有深度吗?
更多推荐
所有评论(0)