生產者消費者模型一(單-單模型)



生產者——消費者問題(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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章