✅ 简介
std::condition_variable
是 C++11 引入的线程间通信机制,允许线程在某个条件满足时被唤醒。- 通常与
std::mutex
一起配合使用,用于实现生产者-消费者模型、线程等待任务等场景。
🔄 基本原理
- 一个线程调用
wait()
进入阻塞状态,直到另一个线程调用notify_one()
或notify_all()
。 wait()
会自动释放传入的mutex
,并在被唤醒时重新获取锁。
⚠️ 虚假唤醒(Spurious Wakeup)
-
调用
wait()
的线程有可能在没有收到通知时被唤醒 ,这被称为虚假唤醒。 -
因此,推荐使用带谓词版本的
wait(lock, predicate)
形式:cppcv.wait(lock, []{ return 条件满足; });
-
这样即使发生虚假唤醒,
wait
也会再次检查条件是否成立,确保线程只有在需要时才继续执行。
🔧 使用方式
示例:生产者-消费者模型(含虚假唤醒处理)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <csignal>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> dataQueue;
std::atomic<bool> stop{false};
// 信号处理函数,捕获 Ctrl+C
void signalHandler(int signum) {
stop = true;
cv.notify_all(); // 通知所有等待的线程
}
void producer() {
int i = 0;
while (!stop) {
{
std::unique_lock<std::mutex> lock(mtx);
dataQueue.push(i);
std::cout << "Produced: " << i << std::endl;
++i;
}
cv.notify_one(); // 通知一个等待的线程
std::this_thread::sleep_for(std::chrono::seconds(1)); // 休眠 1 秒
}
cv.notify_all(); // 通知消费者停止
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !dataQueue.empty() || stop; }); // 等待数据或停止信号
if (!dataQueue.empty()) {
std::cout << "Consumed: " << dataQueue.front() << std::endl;
dataQueue.pop();
lock.unlock(); // 提前解锁以减少锁持有时间
std::this_thread::sleep_for(std::chrono::seconds(1)); // 休眠 1 秒
} else if (stop) {
break; // 队列为空且收到停止信号,退出
}
}
}
int main() {
// 注册信号处理函数
std::signal(SIGINT, signalHandler);
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
☑️ 关键函数说明
函数名 | 说明 |
---|---|
wait(lock) |
等待并释放锁,直到 notify_one 被调用。⚠️ 可能发生虚假唤醒。 |
wait(lock, predicate) |
带条件的等待,直到 predicate 返回 true。✅ 推荐用法 |
notify_one() |
唤醒一个等待的线程。 |
notify_all() |
唤醒所有等待的线程。 |
📌 总结
特性 | 描述 |
---|---|
同步机制 | 用于线程之间的通信 |
等待效率 | 阻塞等待,不占用 CPU |
虚假唤醒 | 可能无通知就被唤醒,需使用谓词保护 |
适用场景 | 生产者-消费者、线程池任务调度等 |
配套使用 | std::mutex + std::unique_lock 配合 |