Linux OS:基于阻塞队列的生产者消费者模型

Linux OS:基于阻塞队列的生产者消费者模型

  • 前言
  • 一、阻塞队列的大致框架
  • 二、生产者向阻塞队列中生产数据
  • 三、消费者获取阻塞队列中数据
  • 四、总体生产和消费思路及测试代码
    • 4.1 单生产单消费
    • 4.2 多生产多消费
  • 五、所以代码

前言

 阻塞队列是一种常用于实现生产者消费者模型的数据结构。和普通队列不同的时,队列存在上限,当队列未满时,往队列中插入数据的操作会被阻塞;当队列为空时,从队列中获取数据的操作也会被阻塞!

  • 在Linux OS:线程封装 | RAII封装锁 | 随机数运算任务封装中,对锁进行了封装,后续加锁解锁操作都基于此!

一、阻塞队列的大致框架

 对于阻塞队列BlockQueue我们首先需要一个普通队列作为生产消费场所!阻塞队列存在上限,我们也需要指明。

 消费者和生产者之间都需要向队列进行操作(插入和获取数据),即访问临界区资源。生产者和消费者并发访问临界资源时会导致多执行流数据不一致问题。所以我们需要对队列进行加锁!

 对于生产者来说,空间就是资源;对于消费者来说,队列中的数据才是资源。在阻塞队列中,只要队列没有到达上限,生产者就可以一直生产;只要队列中有数据,消费者就可以一直消费数据!但存在队列未满,为空情况。此时生产者和消费者会疯狂进行加锁和解锁,访问无意义的临界资源!所以为了防止这种情况出现,我们在生产者和消费者中添加条件变量!当队列为空时,消费者阻塞等待;当队列未满时,生产者阻塞等待!并且生产者生产数据后,直接通知消费者进行消费;消费者消费完后,立即通知生产者生产。

 然后我们需要在构造函数中对锁和条件变量进行初始化,析构时进行回收!具体如下:

const int defaultSize = 5; // 阻塞队列默认大小template <class T>
class BlockQueue
{
public:BlockQueue(int cap = defaultSize): _capacity(cap){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_p_cond, nullptr);pthread_cond_init(&_c_cond, nullptr);}~BlockQueue(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_p_cond);pthread_cond_destroy(&_c_cond);}private:std::queue<T> _q;int _capacity; // 阻塞队列上限大小pthread_mutex_t _mutex;pthread_cond_t _p_cond; // 生产者使用pthread_cond_t _c_cond; // 消费者使用
};

二、生产者向阻塞队列中生产数据

 生产者向临界区(队列资源)中插入数据时,先申请锁,然后判断队列中是否未满。如果队列未满,此时生产者在条件变量出进行等待,一旦消费者消费数据发送信号后就会被唤醒,继续向后执行!当生产者插入完数据后,通知消费者消费,即唤醒消费者的条件变量!最后就是是否锁资源了!

 bool Full(){return _q.size() == _capacity;}void Push(T &in){{LockGuard lock(&_mutex);// pthread_mutex_lock(&_mutex);while (Full()){pthread_cond_wait(&_p_cond, &_mutex);}_q.push(in);pthread_cond_signal(&_c_cond); // 通知消费者消费// pthread_mutex_unlock(&_mutex);}}

三、消费者获取阻塞队列中数据

 消费者行为和生产者类似:申请锁,判断队列中是否存在数据(不存在,消费者在条件变量处阻塞等待),获取队列数据,唤醒生产者条件变量、释放锁!

bool Empty()
{return _q.size() == 0;
}void Pop(T *out)
{{LockGuard lock(&_mutex);// pthread_mutex_lock(&_mutex);while (Empty()){pthread_cond_wait(&_c_cond, &_mutex);}*out = _q.front();_q.pop();pthread_cond_signal(&_p_cond); // 通知生成者生产// pthread_mutex_unlock(&_mutex);}
}

四、总体生产和消费思路及测试代码

4.1 单生产单消费

 在阻塞队列BlockQueue中我们封装了向队列中插入数据和获取数据接口,并在文章开始封装了一个随机数运算任务封装类。

 下面我们在主线程中分布创建一个生产者和消费者线程,并通过参数方式让两个线程看到同一份公共资源 —— 阻塞队列。然后生产者每隔一秒生产一个任务放到阻塞队列中(两个随机数加随机运算符构成的任务);消费者直接获取阻塞队列中的数据,并进行处理!

【测试代码】:

const std::string opers = "+-*[/{%]0";void *Productor(void *args)
{BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);while (true){sleep(1);int data_x = rand() % 10;usleep(1000);int data_y = rand() % 10;char op = opers[rand() % opers.size()];Task t(data_x, data_y, op); // 向阻塞队列中生产数据std::cout << "Productor push task: " << t.PrintTask() << std::endl;bq->Push(t);}
}void *Consumer(void *args)
{BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);while (true){Task t;bq->Pop(&t); // 获取数据t(); // 对数据进行处理std::cout << "Consumer do task done: " << t.PrintResult() << std::endl;}
}int main()
{srand(time(nullptr) ^ pthread_self() ^ getpid());pthread_t p, c;BlockQueue<Task> *bq = new BlockQueue<Task>(); // 阻塞队列pthread_create(&p, nullptr, Productor, (void *)bq); // 创建生产者线程pthread_create(&c, nullptr, Consumer, (void *)bq);  // 创建消费者线程pthread_join(p, nullptr);pthread_join(c, nullptr);return 0;
}

【运行结果】:请添加图片描述

4.2 多生产多消费

单生产单消费多生产多消费一样,不同之处在于我们需要通过数组将生产者和消费者管理起来罢了!
【伪代码】:

int main()
{srand(time(nullptr) ^ pthread_self() ^ getpid());pthread_t p[3], c[2]; // 管理多生产者和多消费者BlockQueue<Task> *bq = new BlockQueue<Task>(); // 阻塞队列pthread_create(&p[0], nullptr, Productor, (void *)bq); // 创建生产者线程pthread_create(&p[1], nullptr, Productor, (void *)bq); // 创建生产者线程pthread_create(&p[2], nullptr, Productor, (void *)bq); // 创建生产者线程pthread_create(&c[0], nullptr, Consumer, (void *)bq);  // 创建消费者线程pthread_create(&c[1], nullptr, Consumer, (void *)bq);  // 创建消费者线程pthread_join(p[0], nullptr);pthread_join(p[1], nullptr);pthread_join(p[2], nullptr);pthread_join(c[0], nullptr);pthread_join(c[1], nullptr);return 0;
}

五、所以代码

gitee: Linux OS:基于阻塞队列的生产者消费者模型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392971.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

低代码: 系统开发准备之确定一般开发流程,需求分析,复杂度分析,标准开发流程

概述 低代码系统开发之前&#xff0c;我们首先要进行一些准备我们首先知道我们软件开发的一般流程同时&#xff0c;我们还要知道&#xff0c;我们整个系统平台的需求如何之后&#xff0c;我们要基于需求进行设计&#xff0c;包含UI设计与系统架构设计 一般开发流程 系统开发…

电路中电阻,电容和电感作用总结

电阻作用 1&#xff0c;上拉电阻 电阻的连接一般是一端接上拉的电源&#xff08;一般与芯片信号的电压值相匹配&#xff09;&#xff0c;另一端连接芯片引脚所对应的信号大概如下图 功能&#xff1a;一、预置某些引脚的功能&#xff0c;例如复位信号拉高&#xff08;失能&…

在 VueJS 中使用事件委托处理点击事件(事件委托,vue事件委托,什么是事件委托,什么是vue的事件委托)

前言 在开发 Vue 项目时&#xff0c;我们经常需要处理大量的点击事件。为每个可点击的元素单独添加事件监听器不仅会增加代码的复杂度&#xff0c;还会降低性能。事件委托是一种有效的优化方式&#xff0c;它可以显著减少事件监听器的数量&#xff0c;提高代码的可维护性和执行…

用Python+selenium实现一个自动化测试脚本

一,安装Python. python官方下载地址&#xff1a;Download Python | Python.org 安装后点击开始菜单,在菜单最上面能找到IDLE. IDLE是python自带的shell, 点击打开, 即可开始编写python脚本了. 二,安装selenium 上面python已安装完成,接下来安装selenium. 安装selenium之前需要…

P1105 平台

平台 题目描述 空间中有一些平台。给出每个平台的位置&#xff0c;请你计算从每一个平台的边缘落下之后会落到哪一个平台上。 注意&#xff0c;如果某两个平台的某个两边缘横坐标相同&#xff0c;物体从上面那个平台落下之后将不会落在下面那个平台上&#xff08;即平台的范…

网络工具(Netcat、iPerf)

目录 1. Netcat2. iPerf 1. Netcat Netcat 是一款简单的 Unix 工具&#xff0c;常用于测试 UDP 和 TCP 连接。 https://www.cnblogs.com/yywf/p/18154209 https://eternallybored.org/misc/netcat/ https://nmap.org/download.html 创建UDP监听端 nc -u -l localPort 创建UDP…

业务开发之用户管理(七)

云风网 云风笔记 云风知识库 首先从逻辑上&#xff0c;用户管理只限制admin用户显示 一、路由限制用户管理的访问权限 config/routes.ts添加access&#xff1a;admin权限限制 {name: userManage,icon: table,access: canAdmin,path: /userManage,component: ./userManage,}二…

Flink 实时数仓(四)【DWD 层搭建(二)流量域事实表】

前言 昨天刚搬到新校区&#xff0c;新校区小的可怜&#xff0c;好在之后出去实习交通可以方便点&#xff1b;待在学院太受限了&#xff0c;早点离开&#xff01; 今天开始完成 DWD 层剩余的需求&#xff0c;上一节我们把日志数据根据不同类型分流写入到了不同的主题&#xff1b…

云端医疗解决方案:互联网医院系统的云计算架构与实现

随着云计算技术的成熟和普及&#xff0c;医疗行业开始探索云端解决方案&#xff0c;以应对数据存储、计算能力和系统扩展性等方面的挑战。互联网医院系统作为医疗信息化的重要组成部分&#xff0c;通过云计算架构实现了高效、灵活和可扩展的医疗服务。本文将深入探讨互联网医院…

2024 AI开发者大赛火热进行中!

“iFLYTEK AI 开发者大赛”是由科大讯飞发起&#xff0c;中国信息协会联合主办的人工智能竞赛平台&#xff0c;汇聚产学研各界力量&#xff0c;面向全球开发者发起数据算法及创新应用类挑战&#xff0c;推动人工智能前沿科学研究和创新成果转化&#xff0c;培育人工智能产业人才…

YOLOv10改进 | 主干篇 | YOLOv10引入CVPR2023 顶会论文BiFormer用于主干修改

1. 使用之前用于注意力的BiFormer在这里用于主干修改。 YOLOv10改进 | 注意力篇 | YOLOv10引入BiFormer注意力机制 2. 核心代码 from collections import OrderedDict from functools import partial from typing import Optional, Union import torch import torch.nn as n…

如何评估并选择最佳的国内项目管理软件?

国内外主流的10款国内项目管理软件对比&#xff1a;PingCode、Worktile、Jira 、Basecamp、Trello、Asana 、Wrike、Tower 、禅道、Teambition 。 在选择适合自己企业的项目管理软件时&#xff0c;很多人会感到无从下手&#xff0c;担心无法找到既符合预算又能满足团队需求的解…

上网防泄密,这些雷区不要碰!九招教你如何防泄密

李明&#xff1a;“最近看到不少关于信息泄露的新闻&#xff0c;真是让人担忧。咱们在工作中&#xff0c;稍有不慎就可能触碰到泄密的雷区啊。” 王芳&#xff1a;“确实&#xff0c;网络安全无小事。尤其是我们这种经常需要处理敏感信息的岗位&#xff0c;更得小心谨慎。那你…

一行代码教你使用Python制作炫酷二维码

二维码&#xff0c;我们日常生活中随处可见的编码方式&#xff0c;凭借其方便快捷的信息承载能力&#xff0c;已经渗透到各行各业。 MyQR 的介绍 MyQR 是一个 Python 库&#xff0c;用于生成自定义二维码&#xff0c;包括带有 Logo、彩色和动态的二维码。它基于 Python 的 qr…

书生大模型实战营第三期——入门岛——Git基础知识

第三关&#xff1a;Git基础知识 任务如下&#xff1a; 任务描述 破冰活动&#xff1a;自我介绍 每位参与者提交一份自我介绍。 提交地址&#xff1a;GitHub - InternLM/Tutorial: LLM&VLM Tutorial 的 camp3 分支&#xff5e;实践项目&#xff1a;构建个人项目 创建一个个人…

电脑硬盘坏了数据可以恢复吗?如何恢复硬盘数据?

电脑硬盘坏了数据可以恢复吗&#xff1f;对于这种问题&#xff0c;还需要具体问题具体分析的&#xff0c;一般是可以恢复。 硬盘损坏可以分为物理损坏和逻辑损坏两种情况&#xff1a; 1.逻辑损坏 这通常是由于软件问题&#xff0c;如文件系统错误、病毒攻击、误删除、格式化等…

未发先火,Smartbi AIChat频频“出圈”

近日&#xff0c;思迈特正式官宣&#xff0c;将于8月8日线上新品发布会上推出自研的全新AI应用——Smartbi AIChat&#xff0c;这款应用在还未正式推向市场前&#xff0c;已获得媒体、分析机构等多方关注&#xff0c;热度飙升&#xff0c;思迈特软件及其新品再一次成为业界内外…

社交媒体分享预览图片和内容修改

在facebook发帖分享链接时&#xff0c;设置预览图片和内容 设置预览图片和内容 <head> <meta name"description" content"我是内容" /> </head> <body><img src"./1.jpg" alt"SEO Image" style"dis…

VSCode在windows系统下使用conda虚拟环境配置

如何解决CondaError: Run ‘conda init‘ before ‘conda activate‘_condaerror: run conda init before conda activat-CSDN博客 首先检查自己的anaconda是否是添加到整个的环境变量里了 打开cmd如果conda和python都能够识别那么就是配置成功了 然后看插件是否安装&#xf…

SQL注入实例(sqli-labs/less-9)

0、初始页面 1、爆库名 使用python脚本 def inject_database1(url):name for i in range(1, 20):low 32high 128mid (low high) // 2while low < high:payload "1 and if(ascii(substr(database(),%d,1)) > %d ,sleep(2),0)-- " % (i, mid)res {"…