好的,我们来详细探讨C++11标准库中的std::condition_variable(条件变量)。
🧩 一、条件变量是什么?
std::condition_variable 是C++11引入的线程同步原语,用于实现线程间的等待/通知机制。它允许一个或多个线程阻塞等待,直到被其他线程通知某个条件成立(或超时)。它通常与std::mutex和std::unique_lock配合使用。
🔑 二、核心方法
wait(unique_lock<mutex>& lock)
- 当前线程阻塞,直到被notify_one()或notify_all()唤醒。
- 在阻塞前,会自动释放传入的锁lock。
- 被唤醒后,在返回前会重新获取锁lock。
- 存在虚假唤醒的可能(即使未被通知也可能唤醒),因此通常需要在循环中检查条件。
wait(unique_lock<mutex>& lock, Predicate pred)
- 带谓词(Predicate)的重载版本。
- 等价于:
while (!pred()) {
wait(lock);
} - 能自动处理虚假唤醒,推荐使用此版本。
notify_one()
- 唤醒一个正在等待此条件变量的线程(如果有多个在等待,具体唤醒哪个不确定)。
- 通常用于只有一个线程能处理被满足的条件时。
notify_all()
- 唤醒所有正在等待此条件变量的线程。
- 通常用于多个线程都能处理被满足的条件时。
wait_for / wait_until
- 带超时功能的等待。允许线程在指定时间段内或被通知时唤醒,避免永久阻塞。
🧠 三、使用模式(生产者-消费者示例)
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
bool done = false; // 标记是否所有数据生产完毕
// 生产者线程
void producer() {
for (int i = 0; i < 10; ++i) {
{
std::lock_guard<std::mutex> lk(mtx);
data_queue.push(i);
std::cout << "Produced: " << i << std::endl;
} // lock_guard 离开作用域自动解锁
cv.notify_one(); // 通知一个消费者
}
{
std::lock_guard<std::mutex> lk(mtx);
done = true; // 设置生产完成标志
}
cv.notify_all(); // 通知所有消费者可能结束
}
// 消费者线程
void consumer() {
while (true) {
std::unique_lock<std::mutex> lk(mtx); // 必须用 unique_lock,因为 wait 会解锁
// 等待条件:队列不为空 或 生产者已结束
cv.wait(lk, []{ return !data_queue.empty() || done; });
// 检查是否结束且队列为空
if (done && data_queue.empty()) {
break;
}
// 处理数据
if (!data_queue.empty()) {
int data = data_queue.front();
data_queue.pop();
std::cout << "Consumed: " << data << " by thread " << std::this_thread::get_id() << std::endl;
}
lk.unlock(); // 处理完数据后可以提前解锁
// 模拟处理耗时
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
std::thread prod(producer);
std::thread cons1(consumer);
std::thread cons2(consumer);
prod.join();
cons1.join();
cons2.join();
return 0;
}
⚠️ 四、重要注意事项
- 在调用notify_one()或notify_all()时,不强制要求持有锁。但持有锁时通知可以避免一些竞态条件(例如,在检查条件后、开始等待前发生通知)。
- 在修改条件(如设置done或修改data_queue)时,必须持有锁。
💡 五、总结
std::condition_variable是实现线程间高效协作(特别是生产者-消费者模型)的关键工具。正确使用它需要理解其与互斥锁的配合、等待谓词的检查以及通知的时机。务必使用带谓词的wait来避免虚假唤醒问题。
网硕互联帮助中心

评论前必须登录!
注册