基于阻塞队列的生产者-消费者模型实现详解
创作时间:
作者:
@小白创作中心
基于阻塞队列的生产者-消费者模型实现详解
引用
CSDN
1.
https://blog.csdn.net/2301_79465388/article/details/146163027
阻塞队列(Blocking Queue)是实现生产者-消费者模型的重要数据结构,它允许生产者和消费者并发地进行数据生产和消费操作。本文将详细介绍基于阻塞队列的生产者-消费者模型的实现,包括模型的特点、代码实现以及多线程环境下的性能优化。
生产者消费者模型特点
生产者-消费者模型是一种经典的并发设计模式,其主要特点如下:
- 一个交易场所:以特定数据结构形式存在的一段内存空间
- 两种角色:生产者(生产线程)和消费者(消费线程)
- 三种关系:
- 生产者之间
- 消费者之间
- 生产者和消费者之间的关系
与阻塞队列结合后形成的特点:
- 同步生产和消费操作:在多线程环境下,生产者和消费者可以同时操作队列,但需要保证线程安全。
- 避免资源浪费:当队列满时,生产者需要等待;当队列空时,消费者需要等待,以此避免资源浪费和无效操作。
- 提高效率:通过设置高水位线和低水位线,适时唤醒多个生产者或消费者,提高生产和消费的效率。
阻塞队列的实现
下面是一个基于C++的阻塞队列实现:
#ifndef __BLOCK_QUEUE__
#define __BLOCK_QUEUE__
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <queue>
using std::cout;
using std::endl;
template <class T>
class BlockQueue
{
private:
bool Isfull()
{
return _queue.size() == _maxcap;
}
bool Isempty()
{
return _queue.empty();
}
public:
BlockQueue(int maxcap = 10)
: _maxcap(maxcap), _queue(), _l_water(0), _h_water(maxcap), _call_num(maxcap / 2)
{
if (maxcap <= 4)
{
_l_water = 0x3f3f3f3f;
_h_water = -0x3f3f3f3f;
_call_num = 1;
}
else
{
_l_water = maxcap / 4;
_h_water = maxcap * 3 / 4;
}
pthread_mutex_init(&_mutex, nullptr);
pthread_cond_init(&_p_cond, nullptr);
pthread_cond_init(&_c_cond, nullptr);
}
void Push(T &in)
{
pthread_mutex_lock(&_mutex);
while (Isfull())
{
pthread_cond_wait(&_p_cond, &_mutex);
}
_queue.push(in);
pthread_cond_signal(&_c_cond);
if (_queue.size() >= _h_water)
{
cout << "call lots comsumer" << endl;
int t = _call_num;
while (t--)
pthread_cond_signal(&_c_cond);
}
pthread_mutex_unlock(&_mutex);
}
void Pop(T *out)
{
pthread_mutex_lock(&_mutex);
while (Isempty())
{
pthread_cond_wait(&_c_cond, &_mutex);
}
*out = _queue.front();
_queue.pop();
pthread_cond_signal(&_p_cond);
if (_queue.size() <= _l_water)
{
cout << "call lots creator" << endl;
int t = _call_num;
while (t--)
pthread_cond_signal(&_p_cond);
}
pthread_mutex_unlock(&_mutex);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_p_cond);
pthread_cond_destroy(&_c_cond);
}
size_t GetSize()
{
return _queue.size();
}
private:
std::queue<int> _queue;
int _maxcap;
pthread_mutex_t _mutex;
pthread_cond_t _p_cond;
pthread_cond_t _c_cond;
int _l_water;
int _h_water;
int _call_num;
};
#endif
成员变量
std::queue<int> _queue:标准库中的队列,用于存储数据。int _maxcap:队列的最大容量。pthread_mutex_t _mutex:互斥锁,用于保证生产和消费操作的互斥,避免数据竞争。pthread_cond_t _p_cond和pthread_cond_t _c_cond:条件变量,分别用于生产者和消费者的等待和唤醒。int _l_water和int _h_water:低水位线和高水位线,用于优化生产和消费的效率。int _call_num:一次性唤醒的生产者或消费者数量。
构造函数
BlockQueue(int maxcap = 10)
- 初始化队列的最大容量和相关参数。
- 根据最大容量设置高水位线和低水位线。
- 初始化互斥锁和条件变量。
Isfull 和 Isempty
bool Isfull():判断队列是否已满。bool Isempty():判断队列是否为空。
Push 函数
void Push(T &in)
- 生产者向队列中添加数据。
- 先获取互斥锁,进入临界区。
- 如果队列已满,生产者在
_p_cond条件变量上等待。 - 向队列中添加数据后,唤醒在
_c_cond条件变量上等待的消费者。 - 如果队列中的数据量达到或超过高水位线,唤醒多个消费者。
- 释放互斥锁,退出临界区。
Pop 函数
void Pop(T *out)
- 消费者从队列中取数据。
- 先获取互斥锁,进入临界区。
- 如果队列为空,消费者在
_c_cond条件变量上等待。 - 从队列中取出数据后,唤醒在
_p_cond条件变量上等待的生产者。 - 如果队列中的数据量低于或等于低水位线,唤醒多个生产者。
- 释放互斥锁,退出临界区。
析构函数
~BlockQueue()
GetSize 函数
size_t GetSize()
总结与多线程分析
这段代码通过互斥锁和条件变量实现了一个线程安全的阻塞队列,能够有效地处理生产者和消费者之间的同步问题。通过设置高水位线和低水位线,可以在数据量较多或较少时适时唤醒多个生产者或消费者,提高队列的使用效率。
对于多线程环境,这段代码可以支持多个生产者和多个消费者。虽然临界区一次只允许一个线程访问,但生产者之间和消费者之间可以并发执行,从而提高整体效率。
生产消费模型的优势
- 协调忙闲不均
- 效率高
- 实现生产者和消费者之间的解耦和
整个系统共用一把锁,意味着一次只能有一个线程访问临界区。多生产多消费相对于单生产单消费而言,高效体现在生产者之间和消费者之间的并发:一个生产者访问队列的时候,其他生产者也在生产数据;消费者访问队列的时候,其他消费者也在消耗数据。
本文原文来自CSDN
热门推荐
电报编码(摩斯电码/中文电报编码)
白色墙面地板搭配指南:三种经典配色方案详解
128平米现代简约风格装修:储物采光为核心,融入中式元素
缓刑:探讨其意义及在我国司法体系中的作用
想要吃到这种美味蘑菇,你可能需要去沙漠挖沙子
金线莲怎么种植,喜欢在湿润的环境中生长
石岭村的旅游开发具有显著的资源优势、潜力和广阔的发展前景
黄金周评:美联储鹰派政策与地缘风险交织,金价能否守住支撑?
主机台式组装最顶配攻略:打造极致性能的DIY电脑
报告显示中国有208万户千万资产的"高净值家庭",未来一年投资首选黄金
范蠡:春秋末期最有头脑的商人
给孩子缴纳城乡医保?这份办理指南请收好
山楂片是碱性还是酸性食物?山楂片的作用和功效及禁忌
十二个月份对应五行属性 八字看月令五行
广州低空飞行航线“上新”,18分钟到机场
如何合理计算电梯房的电梯费用?这些费用标准有哪些实际影响?
韩国空难黑匣子数据丢失,真是让人眼前一黑
香水的主要成分有哪些?人工香精与天然香料有何区别?
洗衣机万物皆能洗吗?这些物品机洗需谨慎
如何区分车牌号1和字母i?
美俄开谈,金价走向何方?投资者如何抉择?
怎么查个体工商户有没有税务登记
个体户营业执照上税号如何查看?
《资金管理翻倍策略》课件
增额终身寿险用于养老规划,存在5个核心缺陷
小型SUV市场遇冷,1月销量无一破万,元UP成黑马排名第二
吃什么蔬菜大便发黑
老人反复发烧怎么办?可能的原因及护理建议
马丘比丘的保姆级攻略,看这篇就够了
外观专利赔偿金额如何确定?