c++11多線程生產者消費者問題

生產者-消費者(producer-consumer)問題,也稱作有界緩衝區(bounded-buffer)問題,兩個進程共享一個公共的固定大小的緩衝區。其中一個是生產者,用於將消息放入緩衝區;另外一個是消費者,用於從緩衝區中取出消息。問題出現在當緩衝區已經滿了,而此時生產者還想向其中放入一個新的數據項的情形,其解決方法是讓生產者此時進行休眠,等待消費者從緩衝區中取走了一個或者多個數據後再去喚醒它。同樣地,當緩衝區已經空了,而消費者還想去取消息,此時也可以讓消費者進行休眠,等待生產者放入一個或者多個數據時再喚醒它。


頭文件:

#include<memory>

#include<chrono>

#include<iostream>

#include<thread>

#include<condition_variable>

#include<mutex>

#include<cstdlib>

#include<chrono>


代碼:


#include "stdafx.h"

class loop_list {

public:

	enum { kItemRepositorySize = 10, kItemsToProduce = 1000};	

private:
	
	struct ItemRepository {

		std::condition_variable repo_not_empty;

		std::condition_variable repo_not_full;

		std::mutex mtx;

		size_t write_position = 0;

		size_t read_position = 0;

		int item_buffer[kItemRepositorySize]{ 0 };

		int cnt = 0;

	};

	typedef struct ItemRepository ItemRepository;

	ItemRepository ir;

	size_t _stop;	//count about pop numbers

public:

	void  push(int  _item) {

		std::unique_lock<std::mutex> lock(ir.mtx);

		while ((ir.write_position+1)% kItemRepositorySize
			
			== ir.read_position){

			std::cout << "please pop..." << std::endl;

			ir.repo_not_full.wait(lock);

		}

		ir.item_buffer[ir.write_position] = _item;

		(ir.write_position)++;

		if (ir.write_position >= kItemRepositorySize)
		
			ir.write_position = 0;

		lock.unlock();

		ir.repo_not_empty.notify_all();
	}


	std::shared_ptr<int> pop(){

		std::unique_lock<std::mutex> lock(ir.mtx);

		while (ir.write_position == ir.read_position) {

			std::cout << "please push..." << std::endl;

			ir.repo_not_empty.wait(lock);

		}
		
		std::shared_ptr<int> _result = std::make_shared<int>(ir.item_buffer[ir.read_position]);

		(ir.read_position)++;

		if (ir.read_position >= kItemRepositorySize)

			ir.read_position = 0;

		lock.unlock();

		ir.repo_not_full.notify_all();

		return _result;

	}

	size_t _count() const {
	
		return _stop;

	}


public:

	loop_list(int _count = kItemsToProduce):_stop(_count) {};

};


//生產者
void ProducerTask(loop_list& ir) {

	for (int i = 1; i <= ir._count(); ++i) {
		
	//	std::this_thread::sleep_for( std::chrono::seconds(2));
		
		std::cout <<"the id : "<<std::this_thread::get_id()<< ". Produce the " << i << "^th item..." << std::endl;

		ir.push(i);

	}
}


//消費者
void ConsumerTask(loop_list& ir,int ProducerTasknumber) //ProducerTasknumber 生產者數目
{
	static int _count = 0;

	while (true) {

	//	std::this_thread::sleep_for(std::chrono::seconds(1));

		auto item = ir.pop();
			
			std::cout << "		Consume the " << *item << "^th item" << std::endl;

		if (++_count == ProducerTasknumber*ir._count()) break;
	}
}


int main(){


	loop_list i;

	std::thread one(ProducerTask, std::ref(i));
	std::thread two(ProducerTask, std::ref(i));
	std::thread thr(ConsumerTask, std::ref(i),2);

	one.join();
	two.join();
	thr.join();

	system("pause");

    return 0;

}


將緩存區封裝成一個類,將所有基本操作賦該類,並決定鎖的粒度。將生產者與消費者操作封裝成函數。生產者消費者互相不知道對方的存在,每個方法只是與緩存區交互。這種寫法,我們在操作時只要確定生產產品與消費產品的數目後,再對操作進行修改,就不會牽一髮而動全身。具有好的封裝性。



部分參考:

點擊打開鏈接


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