C++实现生产者消费者模型
文章目录
- C++实现生产者消费者模型
- 一、生产者消费模型是什么?
- 二、C++代码实现
- 1.引入库和全局变量
- 2.生产者模块
- 3.消费者模块
- 三、完整代码及测试结果
一、生产者消费模型是什么?
生产者-消费者模型是一种用于解决多线程同步问题的经典设计模式,常见于缓冲区管理、任务调度等场景。该模型的核心是两个角色:生产者和消费者。通过共享缓冲区(通常是队列)进行协作。
二、C++代码实现
1.引入库和全局变量
#include <atomic> // 用于原子操作(如无锁递增),防止数据竞争
#include <condition_variable> // 条件变量,用于线程间的等待与通知机制
#include <iostream> // 用于输入输出流操作(例如打印调试信息)
#include <mutex> // 互斥锁,用于保护临界区,防止多个线程同时访问共享资源
#include <queue> // 队列容器,用于存储生产者产生的数据
#include <thread> // 用于创建和管理线程
std::mutex mtx; // 互斥锁,保护对共享队列的并发访问
std::condition_variable pro; // 条件变量,生产者在缓冲区满时等待
std::condition_variable con; // 条件变量,消费者在缓冲区空时等待
std::queue<int> q; // 共享队列,用于存储生产者生成的数据
const int size = 10; // 队列的最大容量(缓冲区大小)
bool done = false; // 控制线程退出的标志变量
std::atomic<int> i(0); // 原子变量,用于保证线程安全的产品编号生成
2.生产者模块
void product() {
while (!done) { // 在没有结束标志时持续生产
int item; // 用于存储生成的产品编号
{
// 加锁,确保对共享资源(队列)的访问是线程安全的
std::unique_lock<std::mutex> lck(mtx);
// 当队列满时,生产者等待,直到队列有空间或程序结束
pro.wait(lck, []{ return q.size() < size || done; });
if (done) break; // 如果设置了退出标志,则跳出循环
// 生成产品编号,使用原子递增保证线程安全
item = ++i;
// 将产品放入队列
q.push(item);
// 输出产品编号,方便观察生产情况
std::cout << "Produced: " << item << std::endl;
}
// 通知消费者有新产品可以消费
con.notify_one();
}
}
3.消费者模块
void consume() {
while (!done) { // 在没有结束标志时持续消费
int item; // 用于存储从队列中取出的产品
{
// 加锁,确保对共享资源(队列)的访问是线程安全的
std::unique_lock<std::mutex> lck(mtx);
// 当队列为空时,消费者等待,直到队列有数据或程序结束
con.wait(lck, []{ return q.size() > 0 || done; });
// 如果设置了退出标志,且队列为空,跳出循环
if (done && q.empty()) break;
// 从队列中取出产品
item = q.front();
q.pop();
// 输出产品编号,方便观察消费情况
std::cout << "Consumed: " << item << std::endl;
}
// 通知生产者有空间可以继续生产
pro.notify_one();
}
}
三、完整代码及测试结果
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
std::mutex mtx;
std::condition_variable pro;
std::condition_variable con;
std::queue<int> q;
const int size = 10;
bool done = false;
std::atomic<int> i(0);
void product() {
while (!done) {
int item;
{
std::unique_lock<std::mutex> lck(mtx);
pro.wait(lck, []{ return q.size() < size || done; });
if (done) break;
item = ++i;
q.push(item);
std::cout << "Produced: " << item << std::endl;
}
con.notify_one();
}
}
void consume() {
while (!done) {
int item;
{
std::unique_lock<std::mutex> lck(mtx);
con.wait(lck, []{ return q.size() > 0 || done; });
if (done && q.empty()) break;
item = q.front();
q.pop();
std::cout << "Consumed: " << item << std::endl;
}
pro.notify_one();
}
}
int main() {
// 创建两个生产者线程
std::thread p1(product);
std::thread p2(product);
// 创建两个消费者线程
std::thread c1(consume);
std::thread c2(consume);
// 让主线程休眠 2 秒,模拟生产和消费过程
std::this_thread::sleep_for(std::chrono::seconds(2));
// 设置退出标志,通知生产者和消费者结束
done = true;
// 唤醒所有等待的线程,以便它们检查退出标志并退出
pro.notify_all();
con.notify_all();
// 等待所有线程结束
p1.join();
p2.join();
c1.join();
c2.join();
return 0;
}
测试结果: