生產者消費者問題(Producer:1、Consumer:1、Buffer:1)
阿新 • • 發佈:2018-12-19
生產者消費者問題是一個著名的執行緒同步問題,該問題描述如下:
有一個生產者在生產產品,這些產品將提供給若干個消費者去消費,為了使生產者和消費者能併發執行,在兩者之間設定一個具有多個緩衝區的緩衝池,生產者將它生產的產品放入一個緩衝區中,消費者可以從緩衝區中取走產品進行消費,顯然生產者和消費者之間必須保持同步,即不允許消費者到一個空的緩衝區中取產品,也不允許生產者向一個已經放入產品的緩衝區中再次投放產品。
先假設生產者和消費者都只有一個,且緩衝區也只有一個。
第一.從緩衝區取出產品和向緩衝區投放產品必須是互斥進行的。可以用關鍵段和互斥量來完成。
第二.生產者要等待緩衝區為空,這樣才可以投放產品,消費者要等待緩衝區不為空,這樣才可以取出產品進行消費。並且由於有二個等待過程,所以要用二個事件或訊號量來控制。
程式碼實現如下:
//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); }