C++实现生产者消费者队列

分析

首先,我们的生产者与消费者队列需要满足同步与互斥关系,就需要一把互斥锁,以及生产者与消费者各自的条件变量。
其次,我们可以利用C++中STL里的queue队列来进行实现,但是我们需要对push,pop进行修改,因为STL库的函数不一定能满足互斥条件。也就是不一定安全。
最后,所有资源在程序结束后一定要记得释放,否则会出现内存泄漏的风险。

程序

队列的类

/thread safe queue
class BlockQueue
{
public:
  BlockQueue(size_t Capacity = CAPACITY)
  {
    _Capacity = Capacity;
    pthread_mutex_init(&_Lock, NULL);
    pthread_cond_init(&_ConsumeCond, NULL);
    pthread_cond_init(&_ProductCond, NULL);
  }
  
  //push == Producer 
  void Push(int& Data)
  {
    pthread_mutex_lock(&_Lock);
    //判断队列有没有满 
    while(IsFull())
    {
      pthread_cond_wait(&_ProductCond,&_Lock);
    }

    _Queue.push(Data);
    pthread_mutex_unlock(&_Lock);
    pthread_cond_signal(&_ConsumeCond);
  }
  
  //pop == consumer
  void Pop(int* Data)
  {
    pthread_mutex_lock(&_Lock);
	
	//判断队列有没有空 
    while(_Queue.empty())
    {
      pthread_cond_wait(&_ConsumeCond, &_Lock); 
    } 

    *Data = _Queue.front();
    _Queue.pop();
    pthread_mutex_unlock(&_Lock);
    pthread_cond_signal(&_ProductCond);
  }

  ~BlockQueue()
  {
    pthread_mutex_destroy(&_Lock);
    pthread_cond_destroy(&_ConsumeCond);
    pthread_cond_destroy(&_ProductCond);
  }
private:
  bool IsFull()
  {
    if(_Queue.size() == _Capacity)
      return true;
    return false;
  }
private:
  queue<int> _Queue;
  size_t _Capacity; // queue max capacity 
  //互斥
  pthread_mutex_t _Lock;//mutex
  //同步 
  pthread_cond_t _ConsumeCond; // consume cond 
  pthread_cond_t _ProductCond; // product _ProductCond 
};

生产者逻辑

void* Producter_start(void* arg)
{
  BlockQueue* que = (BlockQueue*)arg;
  int resource = 1;
  while(1)
  {
    que->Push(resource);
    resource++;
    printf("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    printf("Producter_thread : [%p]\n",pthread_self());
    printf("i product resource [%d]\n",resource - 1);
    printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
  }
  return NULL;

}

消费者逻辑

void* Consumer_start(void* arg)
{
  BlockQueue* que = (BlockQueue*)arg;
  while(1)
  {
    int Data;
    que->Pop(&Data);
    printf("\n\n######################################\n");
    printf("Consumer_thread :  [%p]\n", pthread_self());
    printf("i consume resource [%d]\n", Data);
    printf("######################################\n");
  }
  return NULL;
}

主函数

int main()
{
  BlockQueue* que = new BlockQueue();
  pthread_t com_tid[THREADCOUNT], pro_tid[THREADCOUNT];
  int ret = 0;
  for(int i = 0; i < THREADCOUNT; i++)
  {
    ret = pthread_create(&com_tid[i],NULL,Consumer_start,(void*)que);
    if(ret < 0)
    {
      perror("pthread_create Consumer error");
      return 0;
    }

    ret = pthread_create(&pro_tid[i],NULL,Producter_start,(void*)que);
    if(ret < 0)
    {
      perror("pthread_create Producter error");
    }
  }

  //thread wait 
  for(int i = 0; i < THREADCOUNT; i++)
  {
    pthread_join(com_tid[i],NULL);
    pthread_join(pro_tid[i],NULL);
  }

  //防止内存泄漏 
  delete que;
  que = NULL;
  return 0;
}

结果分析

在这里插入图片描述
我们发现最后的结果中,有一部分生产者与消费者信息的打印好像不是那么规范,但实际上他们都是合理的访问临界资源的。

因为线程之间的抢占式执行,使得每一个线程只能拥有一个CPU资源一小会,然后就需要让出CPU资源给其他线程。然后就会出现上图所示的执行逻辑。

源码地址

https://github.com/duchenlong/linux-text/blob/master/thread/threadqueue.cpp

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值