C++_condition_variable条件变量
·
文章目录
C++_condition_variable条件变量
C++11 引入的线程同步工具,用于实现"等待-通知"机制。当某个条件不满足时,线程可以阻塞等待;当条件满足时,另一个线程发出通知将其唤醒。
核心组成
条件变量必须与互斥锁配合使用,通常包含三个要素:
std::mutex mx; // 互斥锁,保护共享数据
std::condition_variable cv; // 条件变量,负责等待和通知
bool condition = false; // 共享条件(可以是任意类型的条件)
核心API
等待方:wait()
wait() 有三种形式:
// 形式一:无限等待(可能虚假唤醒)
void wait(std::unique_lock<std::mutex>& lock);
// 形式二:带谓词的无限等待(自动处理虚假唤醒)
template<class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
// 形式三:带超时的等待
template<class Rep, class Period>
std::cv_status wait_for(std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time);
// 形式四:带谓词和超时的等待
template<class Rep, class Period, class Predicate>
bool wait_for(std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate pred);
wait()内部行为:
- 自动释放锁 → 让其他线程有机会修改共享条件
- 线程进入阻塞休眠 → 不消耗 CPU
- 被唤醒后,自动重新获取锁 → 保证后续代码的线程安全
- 函数返回
通知方:notify
void notify_one(); // 唤醒一个等待线程(随机选择)
void notify_all(); // 唤醒所有等待线程
虚假唤醒(Spurious Wakeup)
这是一个非常重要的概念:线程可能在没有被通知的情况下意外醒来,这是操作系统层面的行为,C++ 标准允许这种情况发生。
虚假唤醒错误写法(使用if)
std::unique_lock<std::mutex> lock(mx);
if (!ready) { // 虚假唤醒时,条件仍为false,但已经跳出了if
cv.wait(lock);
}
// 继续执行——但条件其实不满足!
虚假唤醒正确写法(用while)
std::unique_lock<std::mutex> lock(mx);
while (!ready) { // 虚假唤醒后,重新检查条件,不满足则继续等待
cv.wait(lock);
}
// 能走到这里,说明条件一定满足
简洁语法(带谓词的 wait)
std::unique_lock<std::mutex> lock(mx);
cv.wait(lock, []{ return ready; }); // 等价于上面的 while 循环
示例
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
using namespace std;
mutex mx;
condition_variable scv;
bool ready = false;
void print_id(int id) {
unique_lock<mutex> lck(mx);
while (!ready) scv.wait(lck); // 如果标志位为false,则阻塞当前线程,直到标志位为true,才继续执行
cout << "thread " << id << endl;
}
void RunFunc() {
unique_lock<mutex> lck(mx);
ready = true; // 设置标志位为true,表示线程可以继续执行
scv.notify_all(); // 唤醒所有等待的线程
}
int main()
{
thread thrs[5];
for (int i = 0; i < 5; i++) {
thrs[i] = thread(print_id, i);
}
cout << "5 threads ready to race...\n";
RunFunc();
for (auto& t : thrs) { // 遍历线程数组中的每一个线程
t.join();
}
return 0;
}
常见陷阱
- 忘记加锁就修改条件 → 数据竞争。
- 先
notify再改条件 → 等待方醒来发现条件不满足,继续等待(可能永久等待)。 - 用
if代替while→ 虚假唤醒导致逻辑错误。 - 用
lock_guard代替unique_lock→ 编译报错,wait()要求unique_lock。 notify时仍持有锁 → 被唤醒的线程立即阻塞,性能下降。
总结
std::condition_variable 的本质就是一个线程间的"消息通知"机制:
- 等待方:
wait()→ 释放锁 + 休眠 + 被唤醒 + 重新加锁。 - 通知方:改条件 →
notify_one() / notify_all()。 - 永远用
while或带谓词的wait()来防止虚假唤醒。 - 必须配合
std::unique_lock<std::mutex>使用。
c++越学越不懂了呀,需借助AI分析别人的c++代码T.T~
更多推荐




所有评论(0)