生产消费者模型概念以及代码

news2024/11/24 12:57:02

概念

何为生产消费者模型?在设计的角度上看,普通的进程间通信,可以认为发送信息与接收信息的人是同步的。

 生产者发信号消费者立刻就会收到。这样的做法虽然提高了效率,但是如果生产者和消费者一旦有一方出现问题就是影响另一方

比如:

 消费者消费数据,生产者也无法运行。必须等等消费者对上次数据处理完毕才并取走数据。

 生产者生产数据消费者就必须等待生产者生产完毕。

所以我们需要中间临时区域。

如果生产者生产快了,就间数据放入中间缓冲区,再去运行生产者后续代码。

如果消费者快了,直接去缓冲区取数据,不用等待生产者发送数据。

虽然多了中间层,需要数据2次转移,但是极大的好处就是,生产者不必等待消费者取数据,消费者也不必等待生产者发送数据,只有在缓冲区为空的时候消费者需要先让生产者生产数据是的串行,其他情况下都是生产者消费者是并发执行。

如果多生产者消费者的出现 

更是极大优化了程序的效率。

生产者1:正在执行生产数据代码

生产者2:获得“生产锁”发送数据到缓冲区

生产者3:未争夺到“生产锁”等待下次争锁,发送数据

消费者1:处理接收到的数据

消费者2:获得“消费锁”取缓冲区一份数据

消费者3:未争夺到“消费锁”等待下次争锁,发送数据

各干各的,只有在同时生产或同时取数据的过程中,同类别的角色才会发送互斥效益。

只有在数据未空或者满的情况下,生产者和消费者才会发送同步情况。

阻塞队列

阻塞队列代码:一把锁,因为他的缓冲区大小不是固定的,消费者生产数据会使得缓冲区大小减小,生产者相反,所以在阻塞队列中我们只能使用一把锁,必须也得互斥。

BlockQueue.hpp

#include <iostream> 
#include <pthread.h>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <string>
#include <signal.h>
#include <fcntl.h>
#include <queue>
using namespace std;

/
//创建自动锁->自动上锁,自动释放锁
class Auto_lock
{
public:
    Auto_lock(pthread_mutex_t* reMax)
        :_AMax(reMax)
    {
        pthread_mutex_lock(_AMax);
    }
    ~Auto_lock()
    {
        pthread_mutex_unlock(_AMax);
    }

private:
    pthread_mutex_t* _AMax;
};
/
//设置等待与唤醒函数
void wait(pthread_cond_t*cond,pthread_mutex_t* mtx)
{
    pthread_cond_wait(cond,mtx);
}

void weekup(pthread_cond_t*cond)
{
    pthread_cond_signal(cond);  
}

/
//建立临界资源与临界区代码
template <class Ty>
class BQueue
{
    //检测bq空与满
    bool empty()
    {
        return _bq.empty();
    }
     bool full()
     {
         return _bq.size()==_capacity;
     }

public:
    BQueue(size_t capacity=5)
        : _capacity(capacity)
        ,_Full(new pthread_cond_t)
        ,_Empty(new pthread_cond_t)
        ,_mtx(new pthread_mutex_t)
        
    {
        //初始化条件变量
        pthread_mutex_init(_mtx,nullptr);
        pthread_cond_init(_Empty,nullptr);
        pthread_cond_init(_Full,nullptr);
    }

    void push(const Ty&x)
    {
        { //放入数据
            Auto_lock am(_mtx);
            while(full()) wait(_Full,_mtx);
            _bq.push(x);
            weekup(_Empty);
        }
    }
    
    void pop(Ty*x)
    {
        {   //取数据
            Auto_lock am(_mtx);
            while(empty()) wait(_Empty,_mtx);
            *x=_bq.front();
            _bq.pop();
            weekup(_Full);
        }
    }

    ~BQueue()
    {
        pthread_mutex_destroy(_mtx);
        pthread_cond_destroy(_Empty);
        pthread_cond_destroy(_Full);
        delete _mtx;
        delete _Empty;
        delete _Full;
    }


private:
    queue<Ty> _bq;
    size_t _capacity;
    pthread_cond_t* _Full;
    pthread_cond_t* _Empty;
    pthread_mutex_t* _mtx;
    pthread_mutex_t* _mtx;
};
/

ConProd.cc

#include"teskblock.hpp"
#include"BlockQueue.hpp"

func_t Tesks[]={Task_1,Task_2,Task_3,Task_4};
/
//生产者线程运行
void*productor(void*ags)
{
    pthread_detach(pthread_self());
    BQueue<func_t>*bq=(BQueue<func_t>*)ags;
    while(1)
    {
        bq->push(Tesks[rand()%4]);
        cout<<" 生产者:"<<pthread_self()<<endl;
        sleep(1);
    }
}
/
//消费者线程运行
void*consumer(void*ags)
{
    pthread_detach(pthread_self());
    BQueue<func_t>*bq=(BQueue<func_t>*)ags;
    while(1)
    {
        func_t ret;
        bq->pop(&ret);
        cout<<" 消费者:"<<pthread_self()<<" ";
        ret();
    }
}
/

int main()
{
    srand((unsigned int)time(0));
    BQueue<func_t> bq(5);
    pthread_t c1,c2,p1,p2;
    pthread_create(&c1,nullptr,consumer,(void*)&bq);
    pthread_create(&c2,nullptr,consumer,(void*)&bq);
    pthread_create(&p1,nullptr,productor,(void*)&bq);
    pthread_create(&p2,nullptr,productor,(void*)&bq);

    while(1);
    
}

test.hpp是任务头文件,这个可以自己写


环形队列

概念为环形的缓冲区,生产区大小固定,消费者只需要在区域中放入数据,消费者也只是取数据,

减少的是有效数据与有效空间。

 4个空间允许4个生产者线程争夺互斥锁

3个数据允许3个消费者线程争夺互斥锁

这里的生产者和消费者们争夺的都是个角色的锁,只有在空间全部放满和所有数据去完的情况下,生产者和消费者才会见面。

P信号量最多7个,C信号量最多7个,C--会让P++,P--会让C--,2种线程不会破坏环形队列的大小,保证了环形队列大小一致性,这样对生产者和消费者做了再一次的解耦操作。

RingQueue.hpp

#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

using namespace std;

const int DNum=7;
class Auto_Lock
{
public:
    Auto_Lock(pthread_mutex_t*lock)
        :_lock(lock)
    {
        pthread_mutex_lock(_lock);
    }
    ~Auto_Lock()
    {
        pthread_mutex_unlock(_lock);
    }
private:
    pthread_mutex_t*_lock;
};

class Auto_Sem
{
public:
    Auto_Sem(sem_t*P,sem_t*V)
        :_P(P)
        ,_V(V)
    {
        sem_wait(_P);

    }
    ~Auto_Sem()
    {
        sem_post(_V);
    }
private:
    sem_t*_P;
    sem_t*_V;
};



template<class Ty>
class RQueue
{
private:
    vector<Ty> _Rq;
    sem_t*_Csem;
    sem_t*_Psem;
    pthread_mutex_t*_Clock;
    pthread_mutex_t*_Plock;
    size_t _index;
    size_t _outdex;

public:
    RQueue(int capacity=5)
        :_Rq(capacity)
        ,_Csem(new sem_t)
        ,_Psem(new sem_t)
        ,_Clock(new pthread_mutex_t)
        ,_Plock(new pthread_mutex_t)
        ,_index(0)
        ,_outdex(0)
    {
        cout<<"_Rq.size()"<<_Rq.size()<<endl;
        pthread_mutex_init(_Plock,nullptr);
        sem_init(_Csem,0,0);
        sem_init(_Psem,0,capacity);
    }
    ~RQueue()
    {
        pthread_mutex_destroy(_Clock);
        pthread_mutex_destroy(_Plock);
        sem_destroy(_Csem);
        sem_destroy(_Psem);
    }
    void push(const Ty&indata)
    {
        Auto_Sem Sem(_Psem,_Csem);
        {
            Auto_Lock Lock(_Plock);
            _Rq[_index++]=indata;
            _index%=DNum;
        }

    }
    void pop(Ty*outdata)
    {
        
        Auto_Sem Sem(_Csem,_Psem);
        {
            Auto_Lock Lock(_Clock);
            *outdata=_Rq[_outdex++];
            _outdex%=DNum;
        }
    }
};

ConProd.cc

#include "RingQueue.hpp"
#include "teskblock.hpp"

func_t Tasks[4]={Task_1,Task_2,Task_3,Task_4};

typedef func_t DataType;


void* consumer(void*ags)
{
    RQueue<DataType>*rq=(RQueue<DataType>*)ags;
    while(1)
    {
        DataType func;
        rq->pop(&func);
        cout<<"consumer:";
        func();
        // cout<<"consumer:"<<func<<endl;
        sleep(1);
    }
}

void* productor(void*ags)
{
    RQueue<DataType>*rq=(RQueue<DataType>*)ags;
    while(1)
    {
        DataType&n=Tasks[rand()%4];
        rq->push(n);
        cout<<"productor:";
        n();
        // cout<<"productor:"<<<<endl;
    }
}

int main()
{
    pthread_t c,p;
    RQueue<DataType>*rq=new RQueue<DataType>(DNum);
    pthread_create(&c,nullptr,consumer,(void*)rq);
    pthread_create(&p,nullptr,productor,(void*)rq);
    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
    delete rq;
}

test.hpp是任务头文件,这个可以自己写


 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OLBY应用APP说明支持

OLBY应用APP说明支持 OLBY是一款支持在线调节鱼缸灯光控制的APP 支持模拟日出日落&#xff0c;给用户在手持端也可以很好的操作控制设备 技术支持 zcj 331163.com

Rancher上的应用服务报错:413 Request Entity Too Large

UI->rancher的ingress->UI前端(在nginx里面)->zuul->server 也就是说没经过一次http servlet 都要设置一下大小 1.rancher的ingress 当出现Request Entity Too Large时&#xff0c;是由于传输流超过1M。 1、需要在rancher的ingress中设置参数解决。 配置注释&a…

微前沿 | 第1期:强可控视频生成;定制化样本检索器;用脑电重建视觉感知;大模型鲁棒性评测

欢迎阅读我们的新栏目——“微前沿”&#xff01; “微前沿”汇聚了微软亚洲研究院最新的创新成果与科研动态。在这里&#xff0c;你可以快速浏览研究院的亮点资讯&#xff0c;保持对前沿领域的敏锐嗅觉&#xff0c;同时也能找到先进实用的开源工具。 本期内容速览 01. 强可…

在线帮助中心也属于知识管理的一种吗?

在线帮助中心是企业或组织为了提供客户支持而建立的一个在线平台&#xff0c;它包含了各种类型的知识和信息&#xff0c;旨在帮助用户解决问题和获取相关的信息。从知识管理的角度来看&#xff0c;可以说在线帮助中心也属于知识管理的一种形式。下面将详细介绍在线帮助中心作为…

Element——table排序,上移下移功能。及按钮上一条下一条功能

需求&#xff1a;table排序&#xff0c;可操作排序上移下移功能。判断第一行上移禁用和最后一行下移禁用&#xff0c;排序根据后端返回的字段 <el-table:data"tableData"style"width: 100%"><el-table-column type"index" label"序…

Docker容器中的Postgresql备份脚本异常解决办法

本文基于K8S中Docker容器对postgres数据库进行备份的操作&#xff0c;编写好脚本后&#xff0c;手动执行脚本是正常的&#xff0c;但是crontab定时实行却报错&#xff0c;报错信息为kubectl command not found&#xff0c;提示没有找到kubectl指令。 本文主要介绍对该报错信息…

Mybatis 复杂结果映射(ResultMap) - 一对多关系映射

上一篇内容我们介绍了Mybatis结果映射&#xff0c;使用结果映射可以在数据库表中字段与类中字段不一致时解决数据映射的问题&#xff0c;本篇我们在上一篇的基础上深入了解结果映射&#xff0c;使用复杂的结果映射解决一对多关系中复杂的数据映射问题。 如果您对结果映射不太了…

长胜证券:看好未来市场情绪和景气度持续修复下的券商板块机遇

摘要 【长胜证券&#xff1a;看好未来商场心情和景气量继续修正下的券商板块机会】买卖佣钱的下调直接下降出资者买卖成本&#xff0c;有望激活商场、提振交投活泼度。一起&#xff0c;当时方针处于良性周期&#xff0c;估计活泼资本商场相关办法有望逐步落地&#xff0c;为券…

专业制造一体化ERP系统,专注于制造工厂生产管理信息化,可定制-亿发

制造业是国民经济的支柱产业&#xff0c;对于经济发展和竞争力至关重要。在数字化和智能化趋势的推动下&#xff0c;制造业正处于升级的关键时期。而ERP系统&#xff0c;即企业资源计划系统&#xff0c;能够将企业的各个业务环节整合起来&#xff0c;实现资源的有效管理和信息的…

No124.精选前端面试题,享受每天的挑战和学习

文章目录 vue中如何获取节点元素&#xff0c;如何获取单个节点&#xff0c;如何获取多个节点vue中的v-for和v-if哪个优先级高&#xff0c;vue2和vue3分开介绍&#xff0c;并说明会产生什么后果介绍一下ts比js的优势&#xff0c;以及在哪些场景用过ts的一些数据类型有什么区别&a…

c#在MVC Api(.net framework)当中使用Swagger,以及Demo下载

主要的步骤就是创建项目&#xff0c;通过nuget 添加Swashbuckle包&#xff0c;然后在SwaggerConfig当中进行相关的配置。 具体的步骤&#xff0c;可以参考下面的链接&#xff1a; https://www.cnblogs.com/94pm/p/8046580.htmlhttps://blog.csdn.net/xiaouncle/article/detail…

代码随想录算法训练营第五十一天|LeetCode503,42

目录 LeetCode 503.下一个更大元素II LeetCode 42.接雨水 LeetCode 503.下一个更大元素II 文章讲解&#xff1a;代码随想录 力扣题目&#xff1a;LeetCode 503.下一个更大元素II 代码如下&#xff08;Java&#xff09;: class Solution {public int[] nextGreaterElements(i…

JZ41数据流在的中位数

题目地址&#x1f4d0;&#xff1a;数据流中的中位数_牛客题霸_牛客网 题目回顾&#x1f4e7;&#xff1a; 解题思路&#x1f4d6;&#xff1a; 首先对于中位数&#xff0c;我们都知道&#xff0c;排序后如果是数组长度是奇数&#xff0c;中位数就是中间的值&#xff0c;也就是…

Camera摄像头PCB布局布线设计注意事项

摄像头&#xff08;Camera或Webcam&#xff09;又称为电脑相机、电脑眼、电子眼等&#xff0c;是一种视频输入设备&#xff0c;被广泛的运用于视频会议、远程医疗及实时监控等方面。摄像头可分为数字摄像头和模拟摄像头两大类&#xff1b; 图1 摄像图模组 摄像头PCB设计注意事项…

数字货币量化交易平台

数字货币量化交易平台是近年来金融科技领域迅速崛起的一种创新型交易方式。它通过应用数学模型和算法策略&#xff0c;实现对数字货币市场的自动交易和风险控制。然而&#xff0c;要在这个竞争激烈的领域中脱颖而出&#xff0c;一个数字货币量化交易平台需要具备足够的专业性&a…

大数据Flink实时计算技术

1、架构 2、应用场景 Flink 功能强大&#xff0c;支持开发和运行多种不同种类的应用程序。它的主要特性包括&#xff1a;批流一体化、精密的状态管理、事件时间支持以及精确一次的状态一致性保障等。在启用高可用选项的情况下&#xff0c;它不存在单点失效问题。事实证明&#…

气传导耳机对耳朵有损害吗?2023热门气传导耳机推荐

​不会对耳朵有损害。无论是在健身房锻炼还是在旅途中&#xff0c;都很多人佩戴蓝牙耳机&#xff0c;蓝牙耳机类型也越来越多&#xff0c;目前气传导耳机领导了耳机的新时尚&#xff0c;它们最突出的优点就是佩戴方式&#xff0c;开放双耳&#xff0c;而气传导耳机采用空气传导…

Python使用 YOLO_NAS_S 模型进行目标检测并保存预测到的主体图片

一、前言&#xff1a; 使用 YOLO_NAS_S 模型进行目标检测&#xff0c;并保存预测到的主体图片 安装包&#xff1a; pip install super_gradients pip install omegaconf pip install hydra-core pip install boto3 pip install stringcase pip install typing-extensions pi…

nginx服务与调优(一)

一、nginx概述&#xff1a; 1.Nginx简介&#xff1a; Nginx是一个高性能的HTTP和反向代理服务器。是一款轻量级的高性能的web服务器/反向代理服务器/电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;单台物理服务器可支持30 000&#xff5e;50 000个并发请求…

混合App开发,还能用计算机之父的那套理论

随着移动互联网的蓬勃发展&#xff0c;传统的原生应用和Web应用逐渐融合&#xff0c;冯诺伊曼结构则为此提供了坚实的理论基础。通过将应用的核心逻辑和数据存储在云端&#xff0c;实现了应用的分离&#xff0c;不仅为开发者带来了更便捷的维护和更新方式&#xff0c;也为用户提…