【C++】多线程(链式、循环队列)实现生产者消费者模式
生产者消费者模式:
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
这是我在Linux多线程中写过的一篇文章,里面详细讲解了信号量和互斥锁解决多线程的生产者与消费者模式:
Linux信号量与互斥锁解决生产者与消费者问题_神厨小福贵!的博客-CSDN博客先来看什么是生产者消费者问题:生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据https://blog.csdn.net/qq_45829112/article/details/121580819下图就是生产者消费者的大致模型:
上图所示,我们能不能在【C++】中使用多线程使得,一边生产,一边消费呢???
关于【C++】多线程,我在之前一篇中说过:
【C++】多线程thread_神厨小福贵!的博客-CSDN博客进程和线程的区别:进程是资源分配的最小单位,线程是CPU调度的最小单位 进程有自己的独立地址空间,线程共享进程中的地址空间 进程的创建消耗资源大,线程的创建相对较小进程的切换开销大,线程的切换开销相对较小 进程:程序执行的过程叫进程。线程:进程内部的一条执行序列或执行路径,一个进程可以包含多条线程(多线程)!每个进程最少有一个线程,例如下面代码:#include <iostream>using namespace std; int main(){ https://blog.csdn.net/qq_45829112/article/details/123521502?spm=1001.2014.3001.5502
下面我们拿链队列和循环队列分别实现我们的生产者消费者模式
链队列实现生产者消费者:queue来实现:
const int MAX_ITEM = 20; //双端队列最大长度
std::mutex mx; //全局锁
std::condition_variable cv; //条件变量cv
class Queue
{
public:void put(int val, int index) //入队函数{std::unique_lock<std::mutex> lock(mx); //类似于智能指针的智能锁,不需要手动解锁while (q.size() == MAX_ITEM) //队列满了之后,等待{cv.wait(lock);}q.push_back(val); //入队cv.notify_all(); //唤醒cout << "producer: " << index << "val : " << "生产者" << val << endl;} int get(int index) //出队函数{unique_lock<std::mutex> lock(mx); //类似于智能指针的智能锁,不需要手动解锁while (q.empty()) //队列空了等待{cv.wait(lock);}int val = q.front(); //出队函数q.pop_front(); //队头出,队尾加cv.notify_all();cout << "Consumer : " << index << " val : " << val << endl;return val;}
private:deque<int> q;
};
void producer(Queue* q, int index)
{for (int i = 0; i < 100; ++i){q->put(i, index); //调用class queue中的put函数std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}
void consumer(Queue* q, int index)
{for (int i = 0; i < 100; ++i){q->get(index); //调用class queue中的get函数std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}
int main()
{Queue* q = new Queue();thread p1(producer, q, 1);thread s1(consumer, q, 1);p1.join();s1.join();return 0;
}
这个代码也比较简单,就不多说了,上面注释也很详细!!!
看一下运行结果:因为我在消费者函数和生产者函数中的睡眠时间都是100,所以我们的生产者和消费者就是生产一个,消费一个这个情况
循环队列实现生产者消费者:
下图是循环队列的大致示意图:
下面来代码:
template<class T> //模板类
class Queue
{enum { QUSIZE = 8 }; //循环队列大小为8T* data; //指针指向循环队列连续空间int front; //队头int rear; //队尾int size; //当前队列的元素个数int maxsize; //队列最大大小
public:Queue() :data(nullptr), front(0), rear(0), size(0), maxsize(QUSIZE){data = new T[maxsize];}~Queue(){free(data);data = nullptr;front = rear = -1;size = 0;maxsize = 0;}int Capt() const { return maxsize; } //求队列最大元素个数的函数int Size() const { return size; } //求现有元素个数的函数bool Empty() const { return Size() == 0; } //判空函数bool Full() const { //判满函数return Size() == maxsize;}bool Push(const T& val) //入队函数{if (Full()) return false;data[rear] = val;rear = (rear + 1) % maxsize; //上面说到最大值为8,也就是说存储下标为0到7size += 1;return true;}bool Front(T& val) //出队函数{if (Empty()) return false;val = data[front];front = (front + 1) % maxsize;//上面说到最大值为8,也就是说存储下标为0到7size -= 1;return true;}
};Queue<int> iq; //实例化iq
std::mutex mx; //全局锁mx
std::condition_variable cv; //条件变量cv
const int maxsize = iq.Capt(); //最大元素个数int number = 0; // 100;
void producer(int index)
{std::unique_lock<std::mutex> lock(mx); //类似于智能指针的智能锁for (int i = 0; i < 100; i++){cv.wait(lock, []()->bool {return !iq.Full(); }); //lambda表达式iq.Push(number); //上述lambda表达式为真退出,所以就不为full时为退出cout << "product " << number << endl;number++;cv.notify_all();}
}void consumer(int index)
{std::unique_lock<std::mutex> lock(mx);for (int i = 0; i < 100; i++){cv.wait(lock, []()->bool {return !iq.Empty(); });//lambda表达式中为真退出等待不为NULL时,退出waitint val = 0;iq.Front(val);cout << "consumer " << val << endl;cv.notify_all();}
}int main(){std::thread pth1(producer, 1); //生产者std::thread pth2(consumer, 2); //消费者pth1.join();pth2.join();return 0;
}
运行结果:
【C++】多线程(链式、循环队列)实现生产者消费者模式相关推荐
- 消息队列:生产者/消费者模式
1.什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接 ...
- Python多线程篇一,theanding库、queue队列、生产者消费者模式爬虫实战代码超详细的注释、自动分配线程对应多任务,GIF演示【傻瓜式教程】
⭐ 简介:大家好,我是zy阿二,我是一名对知识充满渴望的自由职业者. ☘️ 最近我沉溺于Python的学习中.你所看到的是我的学习笔记. ❤️ 如果对你有帮助,请关注我,让我们共同进步.有不足之处请留 ...
- java consumed_Java设计模式—生产者消费者模式(阻塞队列实现)
生产者消费者模式是并发.多线程编程中经典的 真实世界中的生产者消费者模式 生产者和消费者模式在生活当中随处可见,它描述的是协调与协作的关系.比如一个人正在准备食物(生产者),而另一个人正在吃(消费者) ...
- 生产者消费者模式(1)
生产者消费者问题(Producer-consumer problem)是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线程--即所谓的"生产者"和"消 ...
- 多线程-并发编程(7)-生产者消费者模式及非阻塞队列与阻塞队列实现
生产者消费者模式是一个十分经典的多线程协作模式 弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻 存在3个元素 1.生产者(类比厨师) 2.生产者的生产产品(类比美食) 3.消费者(类比吃货) ...
- Java多线程(含生产者消费者模式详解)
多线程 导航 多线程 1 线程.进程.多线程概述 2 创建线程 (重点) 2.1 继承Thread类(Thread类也实现了Runnable接口) 2.2 实现Runnable接口(无消息返回) 2. ...
- java 消费者模式 多线程_[Java并发-24-并发设计模式] 生产者-消费者模式,并发提高效率...
生产者 - 消费者模式在编程领域的应用非常广泛,前面我们曾经提到,Java 线程池本质上就是用生产者 - 消费者模式实现的,所以每当使用线程池的时候,其实就是在应用生产者 - 消费者模式. 当然,除了 ...
- [Linux]生产者消费者模型(基于BlockQueue的生产者消费者模型 | 基于环形队列的生产者消费者模型 | 信号量 )
文章目录 生产者消费者模型 函数调用角度理解生产者消费者模型 生活角度理解生产者消费者模型 为什么要使用生产者消费者模型 生产者消费者模型优点 321原则 基于BlockingQueue的生产者消费者 ...
- 11.python并发入门(part8 基于线程队列实现生产者消费者模型)
一.什么是生产者消费者模型? 生产者就是生产数据的线程,消费者指的就是消费数据的线程. 在多线程开发过程中,生产者的速度比消费者的速度快,那么生产者就必须等待消费者把数据处理完,生产者才会产生新的数据 ...
最新文章
- 一条命令安装Windows Subsystem for Linux
- 忘记Windows系统密码不用急 这个办法轻松帮你破解
- Linux内核的namespace机制分析
- c语言编程学生管理,c语言编程,关于学生管理的程序(急急急)
- Spring Enable批注–编写自定义的Enable批注
- Go 上下文取消操作
- Android性能优化(31)---虚拟机调优
- Educational Codeforces Round 25 E. Minimal Labelshdu1258
- explorer.exe中发生未处理的win32异常
- 输出结果 配置_用单端仪表放大器实现全差分输出
- Ubuntu16.04 安装Redis哨兵模式
- 拍沪牌服务器响应,拍中了四张沪牌,再来聊聊拍牌经验
- java 创建meta inf_java – 在Eclipse中创建META-INF / services文件夹
- ssm实现用户登录功能拦截
- 默认禁用SMB1协议的Samba 4.11-RC1 发布了
- Response学习
- 超详细带你入门开发一个超实用的浏览器插件
- php 分页page
- 简洁但不简单的画册印刷
- C语言课程设计——学生证管理系统