生產者消費者模型(多-多模型/面向對象思想實現)

本篇文章將用c++的面向對象思想,實現生產者消費者模型的代碼編寫。

個人感悟:

1、多生產者多消費者模型的共享競爭關係:
對緩衝區的共享和競爭:
生產者和消費者都需要對共享緩衝區進行操作,存入產品或消費產品。
mtx二值信號量和條件信號量的搭配使用,可以使得生產者或消費者在
第一時間獲取到共享緩衝區的非滿、非空的情況。同時如果緩衝區滿或空
時則停止對應的生產者或消費者的操作,防止死鎖情況的發生。
生產者對生產計數器的競爭:
此時的競爭是生產者內部的競爭,多個生產者同時生產,生產一個則計數器++,同時每一次生產的
產品在緩衝區中存入的位置都是與計數器當前值緊密相關的,用“produce_mutex”信號量鎖住對
produce_item_count變量的訪問權限,可以保證多個生產者對生產的產品的有序裝入,不會發生錯亂。
消費者對消費計數器的競爭:
同上


2、使用面向對象思想構建生產者消費者模型時,則將生產者消費者行爲抽象爲一個工廠模型:
工廠具有倉庫:就是共享緩衝區;
工廠可以生產:就是生產者的工作內容;
工廠可以出貨:就是消費者的工作內容;
因此可以利用工廠類和倉庫類實現一個具有面向對象思想的生產者消費者運行代碼。

代碼實現如下:(IDE : VS2017)


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


static const int kItemRepositorySize = 10; // Item buffer size.
static const int kItemsToProduce = 100;   // How many items we plan to produce.
template<class T>
class Repository {
public:
int item_buffer[kItemRepositorySize]; // 產品緩衝區, 配合 read_position 和 write_position 模型環形隊列.
size_t read_position; // 消費者讀取產品位置.
size_t write_position; // 生產者寫入產品位置.


std::mutex item_counter_mtx_for_producer;//互斥量,保證多個生產者對緩衝區的互斥訪問
size_t item_counter_for_producer; //生產者計數變量


std::mutex item_counter_mtx_for_consumer;//互斥量,保證多個消費者對緩衝區的互斥訪問
size_t item_counter_for_consumer; //消費者計數變量


std::mutex mtx; // 互斥量,保護產品緩衝區
std::condition_variable repo_not_full; // 條件變量, 指示產品緩衝區不爲滿.
std::condition_variable repo_not_empty; // 條件變量, 指示產品緩衝區不爲空.

Repository() 
{
read_position = 0;
write_position = 0;
item_counter_for_producer = 0;
item_counter_for_consumer = 0;
};


void Init() 
{
read_position = 0;
write_position = 0;
item_counter_for_producer = 0;
item_counter_for_consumer = 0;
}
};


template<class T>
class Factory 
{
private:

//共享緩衝區對象
Repository<T> repo;


//生產者生產函數
void ProduceItem(Repository<T> &repo, T item)
{
std::unique_lock<std::mutex> lock(repo.mtx);
while (((repo.write_position + 1) % kItemRepositorySize) == repo.read_position)
{   // item buffer is full, just wait here.
std::cout << "Producer is waiting for an repo_not_full notification...\n";
(repo.repo_not_full).wait(lock); // 生產者等待"產品庫緩衝區不爲滿"這一條件發生.
}


(repo.item_buffer)[repo.write_position] = item; // 寫入產品.
(repo.write_position)++; // 寫入位置後移.
std::cout << "Producer thread: " << std::this_thread::get_id() << "is producing the:" << item << "^th item..." << std::endl;
(repo.item_counter_for_producer)++;


if (repo.write_position == kItemRepositorySize) // 寫入位置若是在隊列最後則重新設置爲初始位置.
repo.write_position = 0;


(repo.repo_not_empty).notify_all(); // 通知消費者產品庫不爲空.
lock.unlock(); // 解鎖.
}


//消費者消費函數
T ConsumeItem(Repository<T> &repo) 
{
T data;
std::unique_lock<std::mutex> lock(repo.mtx);
// item buffer is empty, just wait here.
while (repo.write_position == repo.read_position)
{
std::cout << "Consumer is waiting for an repo_not_empty notification...\n";
(repo.repo_not_empty).wait(lock); // 消費者等待"產品庫緩衝區不爲空"這一條件發生.
}


data = (repo.item_buffer)[repo.read_position]; // 讀取某一產品
(repo.read_position)++; // 讀取位置後移


std::cout << "Consumer thread " << std::this_thread::get_id()
<< " is consuming the " << data << "^th item" << std::endl;


if (repo.read_position >= kItemRepositorySize) // 讀取位置若移到最後,則重新置位.
repo.read_position = 0;


(repo.repo_not_full).notify_all(); // 通知生產者產品庫不爲滿.
lock.unlock(); // 解鎖.


return data; // 返回產品.
}


public:


void Reset() 
{
repo.Init();
}


void ProduceTask() 
{
bool ready_to_exit = false;
while (1)
{
Sleep(1);
std::unique_lock<std::mutex>lock(repo.item_counter_mtx_for_producer);


if (repo.item_counter_for_producer<kItemsToProduce)
{
ProduceItem(repo, repo.item_counter_for_producer);
}
else ready_to_exit = true;


lock.unlock();


if (ready_to_exit == true) {
break;
}
}
cout << "Producer thread " << std::this_thread::get_id()
<< " is exiting..." << endl;
}


void ConsumeTask() {
bool ready_to_exit = false;
while (1)
{
Sleep(1);
std::unique_lock<std::mutex> lock(repo.item_counter_mtx_for_consumer);
if (repo.item_counter_for_consumer < kItemsToProduce)
{
T item = ConsumeItem(repo); // 消費一個產品.
++(repo.item_counter_for_consumer);
}
else ready_to_exit = true;


lock.unlock();


if (ready_to_exit == true) break;
}


cout << "Consumer thread " << std::this_thread::get_id()
<< " is exiting..." << endl;
}
};


int main() {
cout << "Main thread id :" << this_thread::get_id() << endl;
class Factory<int> myfactory;
thread producer1(&Factory<int>::ProduceTask, &myfactory);
thread producer2(&Factory<int>::ProduceTask, &myfactory);
thread producer3(&Factory<int>::ProduceTask, &myfactory);


thread consumer1(&Factory<int>::ConsumeTask, &myfactory);
thread consumer2(&Factory<int>::ConsumeTask, &myfactory);
thread consumer3(&Factory<int>::ConsumeTask, &myfactory);


producer1.join();
producer2.join();
producer3.join();
consumer1.join();
consumer2.join();
consumer3.join();
system("pause");
}

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