悠悠楠杉
C++如何使用std::condition_variable进行线程通信
在现代C++开发中,多线程编程已成为提升程序性能与响应能力的重要手段。然而,多个线程并发执行时,如何安全地共享数据并协调它们的运行顺序,就成了一个关键问题。std::condition_variable 是 C++11 引入的标准库工具之一,专门用于实现线程间的等待与通知机制,是构建高效、可靠线程同步逻辑的核心组件。
std::condition_variable 本身并不用于保护共享资源,而是与 std::mutex 配合使用,实现“条件等待”——即一个或多个线程在某个条件未满足时进入阻塞状态,直到另一个线程修改了共享状态并显式通知它们。这种机制避免了轮询带来的CPU资源浪费,也保证了线程间通信的实时性和准确性。
要理解 std::condition_variable 的工作原理,首先需要掌握其基本使用模式。典型的使用流程包括以下几个步骤:定义一个互斥量(std::mutex)来保护共享数据;定义一个条件变量(std::condition_variable)用于线程间通知;一个表示条件状态的布尔值或具体变量;然后在等待线程中调用 wait() 方法,在唤醒线程中调用 notify_one() 或 notify_all()。
考虑一个经典的生产者-消费者场景:一个线程负责生成数据并放入缓冲区(生产者),另一个线程从缓冲区取出数据处理(消费者)。我们希望当缓冲区为空时,消费者线程自动等待;当有新数据到来时,生产者通知消费者可以继续工作。这时,std::condition_variable 就派上了用场。
cpp
include
include
include
include
include
std::queue
bool finished = false;
void producer() {
for (int i = 0; i < 5; ++i) {
std::thisthread::sleepfor(std::chrono::milliseconds(500));
std::lockguard
std::cout << "生产者: 已生产数据 " << i << std::endl;
cv.notify_one(); // 通知一个等待中的消费者
}
{
std::lock_guard<std::mutex> lock(mtx);
finished = true;
cv.notify_all(); // 通知所有线程任务结束
}
}
void consumer() {
while (true) {
std::uniquelock
if (!data_queue.empty()) {
int value = data_queue.front();
data_queue.pop();
std::cout << "消费者: 已消费数据 " << value << std::endl;
lock.unlock(); // 提前释放锁,减少临界区时间
}
if (finished && data_queue.empty()) {
break;
}
}
std::cout << "消费者: 所有任务已完成。" << std::endl;
}
在这个例子中,cv.wait(lock, predicate) 是关键。它会自动释放锁并使线程休眠,直到被其他线程调用 notify 唤醒。一旦唤醒,它会重新获取锁,并检查谓词(lambda表达式)是否为真。这种“原子性等待”机制确保了不会遗漏通知,也避免了竞态条件。
值得注意的是,wait 可能出现“虚假唤醒”(spurious wakeup),即没有收到 notify 也会被唤醒。因此必须将条件判断写在循环中或使用带谓词的 wait 版本,以确保只有真正满足条件时才继续执行。
此外,notify_one() 用于唤醒一个等待线程,适合一对一通信;而 notify_all() 则唤醒所有等待者,适用于广播场景。选择哪种方式应根据实际需求权衡性能与逻辑复杂度。
总之,std::condition_variable 提供了一种高效、安全的线程协作方式。结合 std::mutex 和合理的条件判断,开发者可以构建出复杂但稳定的并发系统。掌握其使用不仅有助于编写高性能服务程序,也为深入理解现代C++并发模型打下坚实基础。

