生产者消费者模型

目录

生产者消费者模型

为何要使用生产者消费者模型

生产者消费者模型总结: 321原则

生产者消费者模型优点

基于BlockingQueue的⽣产者消费者模型

BlockingQueue

C++ queue模拟阻塞队列的⽣产消费模型

BlockQueue.hpp

main.cc


生产者消费者模型

为何要使用生产者消费者模型

        ⽣产者消费者模式就是通过⼀个容器来解决⽣产者和消费者的强耦合问题。⽣产者和消费者彼此之间不直接通讯,⽽通过阻塞队列来进⾏通讯,所以⽣产者⽣产完数据之后不⽤等待消费者处理,直接扔给阻塞队列,消费者不找⽣产者要数据,⽽是直接从阻塞队列⾥取,阻塞队列就相当于⼀个缓冲区, 平衡了⽣产者和消费者的处理能⼒。这个阻塞队列就是⽤来给⽣产者和消费者解耦的。

生产者消费者模型总结: 321原则

3种关系: 

  • 生产者与生产者 : 互斥
  • 消费者与消费者 : 互斥
  • 生产者与消费者 :互斥与同步

2种角色: 消费者与生产者   

        生产者的职责: 1. 获取数据 2. 传输到交易场所 

        消费者的职责: 1.从交易场所拿数据 2.对数据进行处理

1个场所: 一个交易场所 ,交易场所是临界资源

生产者消费者模型优点

  • 解耦
  • ⽀持并发
  • ⽀持忙闲不均

基于BlockingQueue的⽣产者消费者模型

BlockingQueue

在多线程编程中阻塞队列(Blocking Queue)是⼀种常⽤于实现⽣产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放⼊了元素;当队列满时,往队列⾥存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是 基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)

C++ queue模拟阻塞队列的⽣产消费模型

  • 为了便于理解,我们以单⽣产者,单消费者,来进⾏。 
  • 刚开始写,我们采⽤原始接⼝。
  • 先写单⽣产,单消费。然后改成多⽣产,多消费(这⾥代码其实不变)

BlockQueue.hpp

详细代码(带注释)code/lesson31/2. BlockQueue/BlockQueue.hpp · whb-helloworld/112 - 码云 - 开源中国

#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>

namespace bpModule
{
    template<typename T>
    class BlockQueue
    {
    private:
        bool IsFull(){return _q.size() == _maxcap;}
        bool IsEmpty(){return _q.empty();}
    public:
        BlockQueue(int cap):_maxcap(cap),_cwaitnum(0),_pwaitnum(0)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_producer_cond ,nullptr);
            pthread_cond_init(&_consumer_cond ,nullptr);

        }
        void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            while(IsFull())    //重要重要:防止伪唤醒,通常使用while ,因为伪唤醒时(条件不符合) ,用while可以使得伪唤醒的继续在while中,使其不能向下执行
            {
                _pwaitnum++;
                pthread_cond_wait(&_producer_cond,&_mutex);//前面博客讲了
                _pwaitnum--;
            }
            //生产
            _q.push(in);
            if(_cwaitnum)
            {
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);

        }
        void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())    //防止伪唤醒,通常使用while
            {
                _cwaitnum++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                _cwaitnum--;
            }
            //消费
            *out =_q.front();
            _q.pop();


            //叫醒对方
            if(_pwaitnum)
            {
                pthread_cond_signal(&_producer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }

        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_producer_cond);
            pthread_cond_destroy(&_consumer_cond);
        }

    private:
        std::queue<T> _q;               // 保存数据的容器,临界资源
        int  _maxcap;                   //bp最大容量
        pthread_mutex_t _mutex;         //互斥
        pthread_cond_t  _producer_cond; //生产者条件变量
        pthread_cond_t  _consumer_cond; //消费者条件变量

        int _cwaitnum;
        int _pwaitnum;

    };

}

main.cc

多生产多消费如何实现?

直接加线程数量即可,因为321都维护好了.

#include"BlockQueue.hpp"
#include<unistd.h>
using namespace bpModule;

//消费者
void* consumer(void* args)
{
    BlockQueue<int>* bp =static_cast<BlockQueue<int>* >(args);
    while(true)
    {
        sleep(2);
        //1.从bp拿到数据
        int data;
        bp->Pop(&data);
        //2.处理数据
        printf("Consumer, 消费了一个数据: %d\n", data);
    }


}

//生产者
void* producer(void* args)
{
    BlockQueue<int>* bp =static_cast<BlockQueue<int>* >(args);
    //1.获取数据
    int data =10;
    while(true)
    {
        sleep(1);
        //2.传输数据
        bp->Equeue(data);
        printf("producter 生产了一个数据: %d\n", data);
        data++;
    }
}

单生产,单消费

int main()
{
    BlockQueue<int>* bp =new BlockQueue<int>(5);

    pthread_t c1,p1 ;
    pthread_create(&c1 ,nullptr ,consumer,bp);
    pthread_create(&p1 ,nullptr ,producer,bp);


    pthread_join(c1,nullptr);

    pthread_join(p1,nullptr);


    delete bp;
    return 0;
}


多生产,多消费

int main()
{
    BlockQueue<int>* bp =new BlockQueue<int>(5);

    pthread_t c1 ,c2 ,p1 ,p2 ,p3;
    pthread_create(&c1 ,nullptr ,consumer,bp);
    pthread_create(&c2 ,nullptr ,consumer,bp);

    pthread_create(&p1 ,nullptr ,producer,bp);
    pthread_create(&p2 ,nullptr ,producer,bp);
    pthread_create(&p3 ,nullptr ,producer,bp);



    pthread_join(c1,nullptr);
    pthread_join(c2,nullptr);

    pthread_join(p1,nullptr);
    pthread_join(p2,nullptr);
    pthread_join(p3,nullptr);

    delete bp;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一码归—码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值