Windows 多執行緒(七) 生產者和消費者
阿新 • • 發佈:2019-02-19
本文參考:http://blog.csdn.net/morewindows/article/details/7577591
首先來簡化問題,先假設生產者和消費者都只有一個,且緩衝區也只有一個。這樣情況就簡便多了。
第一.從緩衝區取出產品和向緩衝區投放產品必須是互斥進行的。可以用關鍵段和互斥量來完成。
第二.生產者要等待緩衝區為空,這樣才可以投放產品,消費者要等待緩衝區不為空,這樣才可以取出產品進行消費。並且由於有二個等待過程,所以要用二個事件或訊號量來控制。
#include "stdio.h" #include "process.h" #include "windows.h" //一個生產者,一個消費者,一個緩衝區 //設定控制檯輸出顏色 BOOL SetConsoleColor(WORD wAttributes) { HANDLE hConsole =GetStdHandle(STD_OUTPUT_HANDLE); if(hConsole ==INVALID_HANDLE_VALUE) { return FALSE; } return SetConsoleTextAttribute(hConsole,wAttributes); } const int END_PRODUCE_NUMBER =10; int g_Buffer; //事件與關鍵段 CRITICAL_SECTION g_cs; HANDLE g_hEventBufferEmpty,g_hEventBufferFull; //生產者執行緒函式 unsigned int __stdcall ProducerThreadFun(PVOID pM) { for (int i=1;i<=END_PRODUCE_NUMBER;i++) { //等待緩衝區為空 WaitForSingleObject(g_hEventBufferEmpty,INFINITE); //互斥的訪問緩衝區 EnterCriticalSection(&g_cs); g_Buffer =i; printf("生產者將資料%d放入緩衝區\n",g_Buffer); LeaveCriticalSection(&g_cs); //通知緩衝區有新資料了 SetEvent(g_hEventBufferFull); } return 0; } //消費者執行緒函式 unsigned int __stdcall ConsumerThreadFun(PVOID) { volatile bool flag =true; while (flag) { //等待緩衝區中有資料 WaitForSingleObject(g_hEventBufferFull,INFINITE); //互斥的訪問緩衝區 EnterCriticalSection(&g_cs); SetConsoleColor(FOREGROUND_GREEN); printf(" 消費者從緩衝區中去資料%d\n",g_Buffer); SetConsoleColor(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); if(g_Buffer ==END_PRODUCE_NUMBER) flag =false; LeaveCriticalSection(&g_cs); //通知緩衝區為空 SetEvent(g_hEventBufferEmpty); Sleep(10); } return 0; } int main() { printf(" 生產者消費者問題 1生產者 1消費者 1緩衝區\n"); InitializeCriticalSection(&g_cs); //建立二個自動復位事件,一個表示緩衝區是否為空,另一個表示緩衝區是否已經處理 g_hEventBufferEmpty =CreateEvent(NULL,FALSE,TRUE,NULL); g_hEventBufferFull =CreateEvent(NULL,FALSE,FALSE,NULL); const int THREADNUM =2; HANDLE hThread[THREADNUM]; hThread[0] =(HANDLE)_beginthreadex(NULL,0,ProducerThreadFun,NULL,0,NULL); hThread[1] =(HANDLE)_beginthreadex(NULL,0,ConsumerThreadFun,NULL,0,NULL); WaitForMultipleObjects(THREADNUM,hThread,TRUE,INFINITE); CloseHandle(hThread[0]); CloseHandle(hThread[1]); //銷燬事件和關鍵段 CloseHandle(g_hEventBufferEmpty); CloseHandle(g_hEventBufferFull); DeleteCriticalSection(&g_cs); return 0; }
然後再對這個簡單生產者消費者問題加大難度。將消費者改成2個,緩衝池改成擁有4個緩衝區的大緩衝池。
//1生產者 2消費者 4緩衝區 #include <stdio.h> #include <process.h> #include <windows.h> //設定控制檯輸出顏色 BOOL SetConsoleColor(WORD wAttributes) { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); if (hConsole == INVALID_HANDLE_VALUE) return FALSE; return SetConsoleTextAttribute(hConsole, wAttributes); } const int END_PRODUCE_NUMBER = 8; //生產產品個數 const int BUFFER_SIZE = 4; //緩衝區個數 int g_Buffer[BUFFER_SIZE]; //緩衝池 int g_i, g_j; //訊號量與關鍵段 CRITICAL_SECTION g_cs; HANDLE g_hSemaphoreBufferEmpty, g_hSemaphoreBufferFull; //生產者執行緒函式 unsigned int __stdcall ProducerThreadFun(PVOID pM) { for (int i = 1; i <= END_PRODUCE_NUMBER; i++) { //等待有空的緩衝區出現 WaitForSingleObject(g_hSemaphoreBufferEmpty, INFINITE); //互斥的訪問緩衝區 EnterCriticalSection(&g_cs); g_Buffer[g_i] = i; printf("生產者在緩衝池第%d個緩衝區中投放資料%d\n", g_i, g_Buffer[g_i]); g_i = (g_i + 1) % BUFFER_SIZE; LeaveCriticalSection(&g_cs); //通知消費者有新資料了 ReleaseSemaphore(g_hSemaphoreBufferFull, 1, NULL); } printf("生產者完成任務,執行緒結束執行\n"); return 0; } //消費者執行緒函式 unsigned int __stdcall ConsumerThreadFun(PVOID pM) { while (true) { //等待非空的緩衝區出現 WaitForSingleObject(g_hSemaphoreBufferFull, INFINITE); //互斥的訪問緩衝區 EnterCriticalSection(&g_cs); SetConsoleColor(FOREGROUND_GREEN); printf(" 編號為%d的消費者從緩衝池中第%d個緩衝區取出資料%d\n", GetCurrentThreadId(), g_j, g_Buffer[g_j]); SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); if (g_Buffer[g_j] == END_PRODUCE_NUMBER)//結束標誌 { LeaveCriticalSection(&g_cs); //通知其它消費者有新資料了(結束標誌) ReleaseSemaphore(g_hSemaphoreBufferFull, 1, NULL); break; } g_j = (g_j + 1) % BUFFER_SIZE; LeaveCriticalSection(&g_cs); Sleep(50); //some other work to do ReleaseSemaphore(g_hSemaphoreBufferEmpty, 1, NULL); } SetConsoleColor(FOREGROUND_GREEN); printf(" 編號為%d的消費者收到通知,執行緒結束執行\n", GetCurrentThreadId()); SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); return 0; } int main() { printf(" 生產者消費者問題 1生產者 2消費者 4緩衝區\n"); InitializeCriticalSection(&g_cs); //初始化訊號量,一個記錄有產品的緩衝區個數,另一個記錄空緩衝區個數. g_hSemaphoreBufferEmpty = CreateSemaphore(NULL, 4, 4, NULL); g_hSemaphoreBufferFull = CreateSemaphore(NULL, 0, 4, NULL); g_i = 0; g_j = 0; memset(g_Buffer, 0, sizeof(g_Buffer)); const int THREADNUM = 3; HANDLE hThread[THREADNUM]; //生產者執行緒 hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ProducerThreadFun, NULL, 0, NULL); //消費者執行緒 hThread[1] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun, NULL, 0, NULL); hThread[2] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun, NULL, 0, NULL); WaitForMultipleObjects(THREADNUM, hThread, TRUE, INFINITE); for (int i = 0; i < THREADNUM; i++) CloseHandle(hThread[i]); //銷燬訊號量和關鍵段 CloseHandle(g_hSemaphoreBufferEmpty); CloseHandle(g_hSemaphoreBufferFull); DeleteCriticalSection(&g_cs); return 0; }