生产者与消费者模型

1.三种关系

1.生产者和生产者互斥关系
2.消费者和消费者互斥关系
3.生产者和消费者同步互斥关系

2.生产者和消费者模型

生产者消费者模型就是通过一个容器来来解决强耦合问题的。(耦合:2个或2个以上事物相互作用,相互影响,以至于两个事物在一起的特性和两个事物单独的特性不同)消费者和生产者之间不进行直接通讯,而是通过阻塞队列来通讯的,生产者的数据不用等消费者处理直接扔给阻塞队列,消费者直接去阻塞队列去取数据。阻塞队列相当于一个缓冲区,平衡了消费者和生产者的处理能力,这个阻塞队列就是为消费者和生产者来解耦的。

3.优点
  • 解耦
  • 支持并发
  • 支持忙闲不均
4.实现简单生产者消费者模型
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<vector>

using namespace std;

//实现一个生产者消费者模型
//首先得有一个交易场所
vector<int> data;
pthread_mutex_t mutex;
pthread_cond_t cond;
//生产者
void* Product(void* arg)
{
  (void)arg;
  int count = 0;
  while(1){
    pthread_mutex_lock(&mutex);
    data.push_back(++count) ;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
    usleep(666666);
  }
  return NULL;
}

//消费者
void* Consume(void* arg)
{
  (void)arg;
  //负责把交易场所中的数据取出来
  while(1)
  {
    //每次取最后一个元素
    pthread_mutex_lock(&mutex);
    while(data.empty())
    {
      //1.先释放锁
      //2.等待条件就绪
      //3.如果条件就绪,重新获取锁
      pthread_cond_wait(&cond,&mutex);
    }
    int result = data.back();
    data.pop_back();
    printf("result = %d\n",result);
    pthread_mutex_unlock(&mutex);
    usleep(666666);
  }
  return NULL;
}
int main()
{
  pthread_mutex_init(&mutex,NULL);
  pthread_cond_init(&cond,NULL);
  pthread_t tid1,tid2;
  pthread_create(&tid1,NULL, Product, NULL);
  pthread_create(&tid2,NULL, Consume, NULL);

  pthread_join(tid1,NULL);
  pthread_join(tid2,NULL);

  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&cond);
  return 0;
}
5.基于阻塞队列实现(BlocKingQueue)

BlocKingQueue.hpp

#pragma once

#include<queue>
#include<stdlib.h>
#include<pthread.h>
#include<iostream>
#define NUM 9
using namespace std;
//一般BlockingQueue 都要求长度是有上限的
//如果队列为空,去执行Pop就会堵塞
//如果队列满了,去执行Push也会堵塞

template<class T>
class BlockingQueue
{
private:
  void LockQueue()
  {
    pthread_mutex_lock(&_lock);
  }
  void UnLockQueue()
  {
    pthread_mutex_unlock(&_lock);
  }
  void ProductWait()
  {
    pthread_cond_wait(&_full,&_lock);
  }
  void ConsumeWait()
  {
    pthread_cond_wait(&_empty,&_lock);
  }
  void NotifyProduct()
  {
    pthread_cond_signal(&_full);
  }

  void NotifyConsume()
  {
    pthread_cond_signal(&_empty);
  }
  bool IsEmpty()
  {
    return _queue.size() == 0;
  }
  bool IsFull()
  {
    return _queue.size() == _cap;
  }
public:
  BlockingQueue(int cap = NUM)
    :_cap(cap)
  {
    pthread_mutex_init(&_lock,NULL);
    pthread_cond_init(&_full,NULL);
    pthread_cond_init(&_empty,NULL);
  }

  ~BlockingQueue()
  {
    pthread_mutex_destroy(&_lock);
    pthread_cond_destroy(&_full);
    pthread_cond_destroy(&_empty);
  }
  void Push(const T& data)
  {
    LockQueue(); 
    while(IsFull())
    {
      NotifyConsume();
      cout<<"queue is Full, notify consume data, product stop--size:"<<_queue.size()<<endl;
      ProductWait();
    }
    _queue.push(data);
    UnLockQueue();
  }

  void Pop(T& data)
  {
    LockQueue();
    while(IsEmpty())
    {
      NotifyProduct();
      cout<<"queue is Empty, notify product data,consume stop--size:"<<_queue.size()<<endl;
      ConsumeWait();
    }
    data = _queue.front();
    _queue.pop();
    UnLockQueue();
  }
private:
 queue<T> _queue; 
 int _cap;
 pthread_mutex_t _lock;
 pthread_cond_t _full;
 pthread_cond_t _empty;
};

test.cc

#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include"blockingqueue.hpp"

using namespace std;

void* producter(void* arg)
{
  BlockingQueue<int>* p = (BlockingQueue<int>*) arg;
  srand(time(NULL));
  while(1)
  {
    int data = rand()%100;
    p->Push(data);
    cout<<"product data: "<<data<<endl;
    usleep(666666);
  }
}
void* consumer(void* arg)
{
  BlockingQueue<int>* p = (BlockingQueue<int>*) arg;
  int data;
  while(1)
  {
    p->Pop(data);
    cout<<"consumer data: "<<data<<endl;
    usleep(666666);
  }
}
int main()
{
  pthread_t tid1,tid2;
  BlockingQueue<int> p;

  pthread_create(&tid2,NULL,consumer,&p);
  pthread_create(&tid1,NULL,producter,&p);

  pthread_join(tid1,NULL);
  pthread_join(tid2,NULL);
  return 0;
}

在这里插入图片描述

6.基于循环队列实现(RingQueue)

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。

信号量其实就是一个计数器

RingQueue.hpp

#pragma once
#include<iostream>
#include<vector>
#include<stdlib.h>
#include<semaphore.h>
#include<pthread.h>
#define NUM 9
using namespace std;

template<class T>
class RingQueue{
  public:
    RingQueue(int cap = NUM)
      :_cap(cap)
    {
      _q.resize(cap);
      sem_init(&data_sem,0,0);//初始化信号量,第二个0表示进程间共享
      sem_init(&space_sem,0,cap);//第三个参数表示信号量初始值
      consume_step = 0;
      product_step = 0;
    }
    ~RingQueue()
    {
      sem_destroy(&data_sem);//销毁信号量
      sem_destroy(&space_sem);
    }
    void Push(const T& data)
    {
      sem_wait(&space_sem);//等待信号量,会将信号量的值减一
      _q[consume_step] = data;
      ++consume_step;
      consume_step %= _cap;
      sem_post(&data_sem);//发布信号量,会将信号量的值加一
    }
    void Pop(T& data)
    {
      sem_wait(&data_sem);
      data = _q[product_step];
      ++product_step;
      product_step %= _cap;
      sem_post(&space_sem);
    }
  private:
    vector<T> _q;
    int _cap;
    sem_t data_sem;
    sem_t space_sem;
    int consume_step;
    int product_step;
};

test.cc

#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include"RingQueue.hpp"

using namespace std;

void* producter(void* arg)
{
  RingQueue<int>* p = (RingQueue<int>*) arg;
  srand(time(NULL));
  while(1)
  {
    int data = rand()%100;
    p->Push(data);
    cout<<"product data: "<<data<<endl;
    sleep(1);
  }
}
void* consumer(void* arg)
{
  RingQueue<int>* p = (RingQueue<int>*) arg;
  int data;
  while(1)
  {
    p->Pop(data);
    cout<<"consumer data: "<<data<<endl;
    sleep(1);
  }
}
int main()
{
  pthread_t tid1,tid2;
  RingQueue<int> p;

  pthread_create(&tid2,NULL,consumer,&p);
  pthread_create(&tid1,NULL,producter,&p);

  pthread_join(tid1,NULL);
  pthread_join(tid2,NULL);
  return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值