1. 程式人生 > >生產者消費者問題(Producer:1、Consumer:1、Buffer:1)

生產者消費者問題(Producer:1、Consumer:1、Buffer:1)

生產者消費者問題是一個著名的執行緒同步問題,該問題描述如下:

有一個生產者在生產產品,這些產品將提供給若干個消費者去消費,為了使生產者和消費者能併發執行,在兩者之間設定一個具有多個緩衝區的緩衝池,生產者將它生產的產品放入一個緩衝區中,消費者可以從緩衝區中取走產品進行消費,顯然生產者和消費者之間必須保持同步,即不允許消費者到一個空的緩衝區中取產品,也不允許生產者向一個已經放入產品的緩衝區中再次投放產品。

先假設生產者和消費者都只有一個,且緩衝區也只有一個。

第一.從緩衝區取出產品和向緩衝區投放產品必須是互斥進行的。可以用關鍵段和互斥量來完成。

第二.生產者要等待緩衝區為空,這樣才可以投放產品,消費者要等待緩衝區不為空,這樣才可以取出產品進行消費。並且由於有二個等待過程,所以要用二個事件或訊號量來控制。

程式碼實現如下:

//1生產者 1消費者 1緩衝區  
//使用二個事件,一個表示緩衝區空,一個表示緩衝區滿。  
//再使用一個關鍵段來控制緩衝區的訪問  
#include <stdio.h>  
#include <process.h>  
#include <windows.h>  
 
 
#include<iostream>
#include<iomanip>
using namespace std;
 
//設定控制檯輸出顏色  
//SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wAttributes);  
const int iProduceNumber = 10;//生產產品個數
int iGlobBuffer;//全域性緩衝區
 
 
CRITICAL_SECTION csGlobBuffer;//關鍵段來控制緩衝區的訪問
HANDLE hEventBufferEmpty;//緩衝區空
HANDLE hEventBufferFull;//緩衝區滿
 
 
//生產者執行緒函式
UINT WINAPI ProducerProc(PVOID pParam){
	for(int i = 0; i < iProduceNumber; i++){
		//等待緩衝區為空
		WaitForSingleObject(hEventBufferEmpty, INFINITE);
 
		//互斥的訪問緩衝區
		EnterCriticalSection(&csGlobBuffer);
		iGlobBuffer = (i+1)*100;
		cout << "生產者將資料" << iGlobBuffer << "放入緩衝區" << endl;
		LeaveCriticalSection(&csGlobBuffer);
 
		//通知緩衝區有新資料了
		SetEvent(hEventBufferFull);
		Sleep(10);//主動讓出CPU
	}
	return 0;
} 
//消費者執行緒函式  
UINT WINAPI ConsumerProc(PVOID pParam){
	volatile bool bContinue = true;
	while(bContinue){
		//等待緩衝區中有資料  
		WaitForSingleObject(hEventBufferFull, INFINITE);
 
		//互斥的訪問緩衝區
		EnterCriticalSection(&csGlobBuffer);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
		cout << "消費者從緩衝區中取資料" << iGlobBuffer << endl;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
		if((iGlobBuffer/100) == iProduceNumber)				bContinue = false;
		LeaveCriticalSection(&csGlobBuffer);
 
		//通知緩衝區已為空
		SetEvent(hEventBufferEmpty);
		Sleep(10);//主動讓出CPU
	}
	return 0;
}
 
void main()
{
	InitializeCriticalSection(&csGlobBuffer);
	//自動復位事件,初始的時候緩衝區為空
	hEventBufferEmpty = CreateEventW(NULL, FALSE, TRUE, NULL);
	//自動復位事件,初始的時候緩衝區沒有資料
	hEventBufferFull = CreateEventW(NULL, FALSE, FALSE, NULL);
 
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
 
	HANDLE hThreads[2];
	hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, ProducerProc, NULL, 0, NULL);
	hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, ConsumerProc, NULL, 0, NULL);
	WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
	CloseHandle(hThreads[0]);
	CloseHandle(hThreads[1]);
 
	cout << "主執行緒等待到兩個子執行緒之後就會退出!" << endl;
	///銷燬關鍵段和事件
	DeleteCriticalSection(&csGlobBuffer);
	CloseHandle(hEventBufferEmpty);
	CloseHandle(hEventBufferFull);
}