生产者消费者模型一(单-单模型)



生产者——消费者问题(producer-consumer),又名:有界缓冲区(bounded-buffer)问题
本文介绍单生产者——单消费者的代码实现

设计要点:
 当缓冲区满已满,而此时生产者还想向缓冲区中放入一个新的数据项时。则让生产者睡眠,待消费者从缓冲区中取出一个或多个数据项时再唤醒生产者。
 同样的,当缓冲区满已空,而此时消费者还想从缓冲区中取出一个新的数据项时。则让消费者睡眠,待生产者向缓冲区中放入一个或多个数据项时再唤醒消费者。

代码实现如下:(IDE : VS2017)

#include"stdafx.h"
#include<string>
#include<stdio.h>
#include <stdlib.h>
#include<thread>
#include <mutex>
#include<iostream>
using namespace std;

static const int kItemRepositorySize = 10; // Item buffer size.
static const int kItemsToProduce = 100;   // How many items we plan to produce.

class ItemRepository
{
public:
 int item_buffer[kItemRepositorySize]; // 产品缓冲区, 配合 read_position 和 write_position 模型环形队列.
 size_t read_position; // 消费者读取产品位置.
 size_t write_position; // 生产者写入产品位置.
 std::mutex mtx; // 互斥量,保护产品缓冲区
 std::condition_variable repo_not_full; // 条件变量, 指示产品缓冲区不为满.
 std::condition_variable repo_not_empty; // 条件变量, 指示产品缓冲区不为空.
}gItemRepository; // 产品库全局变量, 生产者和消费者操作该变量.

void ProduceItem(ItemRepository *ir, int item)
{
 std::unique_lock<std::mutex> lock(ir->mtx);
 //初始位置都是 0,当两者相差一个位置时,定义满状态。(最多存储kItemRepositorySize - 1个)
 while (((ir->write_position+1) % kItemRepositorySize)== ir->read_position)
 { // item buffer is full, just wait here.
  std::cout << "Producer is waiting for an repo_not_full notification...\n";
  (ir->repo_not_full).wait(lock); // 生产者等待"产品库缓冲区不为满"这一条件发生.
 }

 std::cout << "Producer is producting the " << item << "^th item..." << std::endl;
 (ir->item_buffer)[ir->write_position] = item; // 写入产品.
 (ir->write_position)++; // 写入位置后移.

 if (ir->write_position == kItemRepositorySize) // 写入位置若是在队列最后则重新设置为初始位置.
  ir->write_position = 0;

 (ir->repo_not_empty).notify_all(); // 通知消费者产品库不为空.

 //条件变量的wait 会自动调用锁的unlock ,此处注释掉效果一样
 lock.unlock(); // 解锁.
}

int ConsumeItem(ItemRepository *ir)
{
 int data;
 std::unique_lock<std::mutex> lock(ir->mtx);
 // item buffer is empty, just wait here.
 while (ir->write_position == ir->read_position)
 {
  std::cout << "Consumer is waiting for an repo_not_empty notification...\n";
  (ir->repo_not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这一条件发生.
 }

 std::cout << "Consumer is consuming the " << ir->read_position << "^th item" << std::endl;
 data = (ir->item_buffer)[ir->read_position]; // 读取某一产品
 (ir->read_position)++; // 读取位置后移

 if (ir->read_position >= kItemRepositorySize) // 读取位置若移到最后,则重新置位.
  ir->read_position = 0;

 (ir->repo_not_full).notify_all(); // 通知生产者产品库不为满.

 //条件变量的wait 会自动调用锁的unlock ,此处注释掉效果一样
 lock.unlock(); // 解锁.

 return data; // 返回产品.
}


void ProducerTask() // 生产者任务
{
 for (int i = 0; i < kItemsToProduce; ++i)
 {
  ProduceItem(&gItemRepository, i); // 循环生产 kItemsToProduce 个产品.
 }
}

void ConsumerTask() // 消费者任务
{
 static int cnt = 0;
 while (1)
 {
  //sleep(1);
  int item = ConsumeItem(&gItemRepository); // 消费一个产品.
  if (++cnt == kItemsToProduce) break; // 如果产品消费个数为 kItemsToProduce, 则退出.
 }
}

void InitItemRepository(ItemRepository *ir)
{
 ir->write_position = 0; // 初始化产品写入位置.
 ir->read_position = 0; // 初始化产品读取位置.
}

int main()
{
 ItemRepository gItemRepository;
 InitItemRepository(&gItemRepository);
 std::thread producer(ProducerTask); // 创建生产者线程.
 std::thread consumer(ConsumerTask); // 创建消费之线程.
 producer.join();
 consumer.join();
 system("pause");
 return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值