Win32API クリティカルセクションとイベントを用いた生産者・消費者パターン
マルチスレッドプログラミングの代表的なデザインパターンである「生産者・消費者パターン」をWin32 APIで実現する。
#include <windows.h> #include <process.h> #include <stdio.h> const int MaxRequest = 10; int iQueue[MaxRequest];//リクエストを溜めておくキュー(待ち行列) int head = 0;//キューの先頭を表すインデックス int tail = 0;//キューの末尾を表すインデックス int count = 0;//キューに格納されているリクエストの数 HANDLE hEventCons;//生産者用イベントオブジェクト HANDLE hEventProd;//消費者用イベントオブジェクト CRITICAL_SECTION cs;//スレッドを同期させるためのクリティカルセクション //キューを介して生産者スレッドが消費者スレッドにリクエスト(整数値)を送るための関数(生産者スレッドから呼ばれる) void PutRequest(int n) { EnterCriticalSection(&cs); //キューに格納されたリクエストの数が最大値に達した場合は //クリティカルセクションをアンロックし待機状態に入る //待機状態から脱出したら、再度ロックを取りwhileループの //継続条件のテストを実施する while (count >= MaxRequest) { LeaveCriticalSection(&cs); WaitForSingleObject(hEventProd, INFINITE); EnterCriticalSection(&cs); } //キューにリクエストを格納する(エンキュー) iQueue[tail] = n; tail = (tail + 1) % MaxRequest; count++; //消費者スレッドにリクエストがキューに格納されたことを通知する SetEvent(hEventCons); LeaveCriticalSection(&cs); } //キューを介して消費者スレッドが生産者スレッドからリクエスト(整数値)を取り出すための関数(消費者スレッドから呼ばれる) int TakeRequest() { EnterCriticalSection(&cs); //キューが空の場合は、クリティカルセクションをアンロックし //待機状態に入る。待機状態から脱出したら、再度ロックを取り //whileループの継続条件のテストを実施する while (count <= 0) { LeaveCriticalSection(&cs); WaitForSingleObject(hEventCons, INFINITE); EnterCriticalSection(&cs); } //キューからリクエストを取り出す(デキュー) int n = iQueue[head]; head = (head + 1) % MaxRequest; count--; //生産者スレッドにキューからリクエストが取り出されたことを通知する SetEvent(hEventProd); LeaveCriticalSection(&cs); return n; } //生産者スレッド //キューを介して、消費者スレッドに対しリクエスト(整数値)を送る unsigned int WINAPI ProducerThread(LPVOID arg) { int n = 0; while (true) { printf("PutRequest: %d\n", n); PutRequest(n++); Sleep(rand() % 1000); } return 0; } //消費者スレッド //キューを介して生産者スレッドから送られたリクエスト(整数値) //を取り出し、コンソールに表示する unsigned int WINAPI ConsumerThread(LPVOID arg) { while (true) { printf("TakeRequest: %d\n", TakeRequest()); } return 0; } int main() { //生産者スレッド、消費者スレッドを起動する const int NumberOfConsThreads = 2; const int NumberOfProdThreads = 10; HANDLE hThreadCons[NumberOfConsThreads]; HANDLE hThreadProd[NumberOfProdThreads]; unsigned int uiConsThreadId; unsigned int uiProdThreadId; //Initialization InitializeCriticalSection(&cs); hEventCons = CreateEvent(NULL, TRUE, FALSE, "Consumer"); hEventProd = CreateEvent(NULL, TRUE, FALSE, "Producer"); //Create consumer threads for (int i = 0; i < NumberOfConsThreads; i++) { hThreadCons[i] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThread, NULL, 0, &uiConsThreadId); } //Create producer threads for (int i = 0; i < NumberOfProdThreads; i++) { hThreadProd[i] = (HANDLE)_beginthreadex(NULL, 0, ProducerThread, NULL, 0, &uiProdThreadId); } //Wait for exit consumer threads for (int i = 0; i < NumberOfConsThreads; i++) { WaitForSingleObject(hThreadCons[i], INFINITE); } //Wait for exit producer threads for (int i = 0; i < NumberOfProdThreads; i++) { WaitForSingleObject(hThreadProd[i], INFINITE); } //Cleanup DeleteCriticalSection(&cs); CloseHandle(hEventCons); CloseHandle(hEventProd); return 0; }