基于阻塞队列的生产者-消费者模型实现详解
创作时间:
作者:
@小白创作中心
基于阻塞队列的生产者-消费者模型实现详解
引用
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
热门推荐
公积金与社保有什么区别?
如何监控改善项目风险管理
马斯克xAI开源大语言模型Grok-1:3140亿参数的MoE架构详解
社工助力社区养老:一个山东村庄的实践案例
资产合同管理制度:确保企业资产安全与合规
《封神演义》:法宝有多大的作用?
大禹治水与定海神针的传说之谜
债权转让的法律效力如何确认
出口美国货物清关指南:流程及注意事项
天珠真的是神药么?心病还须心药治!
“天降”树枝意外伤人,飞来横祸谁该担责?
FlashTool刷机教程:步骤详解与注意事项
口诀 掌诀,牢记二十四节气
芹菜叶子怎么做好吃又简单?15种创意食谱推荐
俄罗斯为何就是防不住乌军的无人机突袭
柜子有味道是甲醛吗?如何检测和去除甲醛?
适合家里养的32种花(多图)
种鸽饲料怎么配?不同季节的科学配方指南
2017年全球城市生活成本调查:上海跌出前十,新加坡蝉联榜首
甲状腺疾病有哪些类型症状
影响信用卡额度提升幅度的关键因素深度解析
日本人怎么看天皇制度?有没人想废除皇室、建立共和国?
请给情感一个宣泄的窗口
毕业论文写作,如何确定一个好的选题,从0开始
交警提醒:可以“换车不换号”了,只需满足3个条件,都能申请成功
怎么调生物钟
血管内皮细胞机械敏感基因在动脉粥样硬化形成和治疗中的研究进展
在职体验:提升职业技能的有效途径
油烟机跑烟的原因与解决方案
张雪峰说北理珠珠海校区:变成985了吗?