c++ 的std::condition_variable
C++ 的 std::conditionvariable,从啥是它到怎么用,一步步讲明白。std::conditionvariable 是 C++11 引入的一个多线程同步工具,跟 std::mutex 搭配,能让线程“等条件”再干活,特别实用。
啥是 std::condition_variable?
想象你在饭店排队买饭,前台说:“饭还没好,等会儿。” 你就站那儿等着,有人喊“饭好了!”你才去拿。std::condition_variable 就像这个“喊话器”:
一个线程等着某个条件(比如“数据准备好”)。 另一个线程干完活,喊一声“好了”,等着的人就醒过来。 简单说:std::condition_variable 是线程间的一个“信号灯”,用来通知“条件满足了”。
为啥用它?
省资源:比忙等(一直循环检查)节约 CPU。
协作:线程间有条件地配合,比如生产者-消费者。
灵活:跟锁一起用,安全又方便。
怎么用?
得包含
1. 基本用法
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false; // 条件
void worker() {
std::unique_lock<std::mutex> lock(mtx); // 上锁
cv.wait(lock, [] { return ready; }); // 等条件
std::cout << "工人醒了,干活!\n";
}
void boss() {
std::this_thread::sleep_for(std::chrono::seconds(1)); // 假装忙1秒
{
std::lock_guard<std::mutex> lock(mtx); // 上锁
ready = true; // 设置条件
}
cv.notify_one(); // 喊一声“好了”
}
int main() {
std::thread t1(worker);
std::thread t2(boss);
t1.join();
t2.join();
return 0;
}
输出:
(等1秒)
工人醒了,干活!
std::condition_variable cv:信号灯对象。
cv.wait(lock, 条件):等着,直到条件为 true,期间解锁让别人干活。
cv.notify_one():喊醒一个等着的线程。
std::uniquelock:比 lockguard 灵活,能配合 wait。
2. 生产者-消费者
经典场景:一个线程生产数据,另一个消费:
#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 = 1; i <= 3; i++) {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(i);
std::cout << "生产: " << i << "\n";
}
cv.notify_one(); // 通知消费者
}
{
std::lock_guard<std::mutex> lock(mtx);
done = true; // 生产完了
}
cv.notify_one();
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !data_queue.empty() || done; }); // 等数据或结束
if (!data_queue.empty()) {
int data = data_queue.front();
data_queue.pop();
std::cout << "消费: " << data << "\n";
lock.unlock(); // 手动解锁(可选)
} else if (done) {
break; // 数据空且生产完了,退出
}
}
std::cout << "消费者下班\n";
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
输出:
(等1秒)
生产: 1
消费: 1
(等1秒)
生产: 2
消费: 2
(等1秒)
生产: 3
消费: 3
消费者下班
wait(lock, 条件):等队列有东西或生产结束。 notify_one():每次生产完喊一声。 done:标记生产完成,避免消费者死等。
3. 加超时
不想一直等,可以加时间限制:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
if (cv.wait_for(lock, std::chrono::seconds(2), [] { return ready; })) {
std::cout << "条件满足,干活\n";
} else {
std::cout << "超时了,不等了\n";
}
}
void boss() {
std::this_thread::sleep_for(std::chrono::seconds(3)); // 故意晚3秒
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
}
int main() {
std::thread t1(worker);
std::thread t2(boss);
t1.join();
t2.join();
return 0;
}
输出:
(等2秒)
超时了,不等了
(再等1秒,boss才通知)
wait_for(lock, 时间, 条件):最多等 2 秒,返回 true(条件满足)或 false(超时)。
4. 通知所有线程
用 notify_all() 喊醒所有等着的线程:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; });
std::cout << "工人 " << id << " 醒了\n";
}
int main() {
std::thread t1(worker, 1);
std::thread t2(worker, 2);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_all(); // 喊醒所有
t1.join();
t2.join();
return 0;
}
输出:
(等1秒)
工人 1 醒了
工人 2 醒了
notify_all():通知所有等着的人。
注意点
必须配锁: wait 需要 std::uniquelock,不能用 lockguard。
伪唤醒: 系统可能无故唤醒线程,所以用条件([] { return ready; })检查。
顺序: 先改条件,再 notify,否则可能错过信号。
性能: 比忙等好,但锁和等待多了也耗时。
需要掌握啥?
基本用法: wait(lock, 条件)、notify_one()。
和锁搭配: std::mutex 和 std::unique_lock。
高级用法: waitfor(超时)、notifyall(全通知)。
场景: 生产者-消费者、线程同步、条件等待。
调试: 注意条件和通知顺序,别漏信号。
总结
std::condition_variable 是线程间的“信号员”,等条件+通知。
用法:配 mutex,wait 等着,notify 喊醒。
适合协作式多线程,现代 C++ 必备。
文档信息
版权声明:可自由转载(请注明转载出处)-非商用-非衍生
发表时间:2025年7月1日 12:25