使用std::condition_variable实现生产者消费者模型,需结合互斥锁保护共享缓冲区,通过条件变量在缓冲区满或空时阻塞线程,并在状态变化时通知等待线程。

在C++中使用std::condition_variable实现生产者消费者模型,是一种典型的线程同步问题。核心目标是让生产者线程在缓冲区满时等待,消费者线程在缓冲区空时等待,通过条件变量和互斥锁配合完成安全的资源访问与通知机制。
基本组件准备
要实现该模型,需要以下几个关键元素:
- std::mutex:保护共享缓冲区,防止数据竞争。
- std::condition_variable:用于线程间通信,通知对方状态变化。
- std::queue 或其他容器:作为共享任务缓冲区。
- 生产者线程函数:向队列添加数据,并通知消费者。
- 消费者线程函数:从队列取出数据,若为空则等待。
代码实现示例
下面是一个使用固定大小缓冲区的简单实现:
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv;
const int MAX_SIZE = 5;
void producer(int id) {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [](){ return buffer.size() < MAX_SIZE; });
buffer.push(i);
std::cout << "Producer " << id << " produced: " << i << "\n";
lock.unlock();
cv.notify_all(); // 通知所有等待的消费者
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void consumer(int id) {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [](){ return !buffer.empty(); });
int value = buffer.front();
buffer.pop();
std::cout << "Consumer " << id << " consumed: " << value << "\n";
lock.unlock();
cv.notify_all(); // 通知生产者可以继续生产
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
}
主函数启动多个生产者和消费者线程:
立即学习“C++免费学习笔记(深入)”;
int main() {
std::thread p1(producer, 1);
std::thread p2(producer, 2);
std::thread c1(consumer, 1);
std::thread c2(consumer, 2);
p1.join();
p2.join();
c1.join();
c2.join();
return 0;
}
关键点说明
使用condition_variable时需要注意以下几点:
-
必须配合unique_lock使用:
wait()、notify_one()、notify_all()都要求传入std::unique_lock<std::mutex>。 -
使用lambda判断条件:避免虚假唤醒,将条件判断写在
wait()的第二个参数中。 -
及时通知对方:每次修改共享状态后调用
notify_all()或notify_one(),确保等待线程能被唤醒。 - 注意notify的位置:可以在持有锁时调用,也可以释放锁后调用,但需保证逻辑正确。
基本上就这些。只要掌握好互斥锁保护数据、条件变量等待事件、及时通知这三个核心环节,就能写出稳定的生产者消费者模型。











