【C言語】マルチスレッドの排他処理
Win32API
CreateEvent()
SetEvent
CreateThread()
WaitForSingleObject()
WaitForMultipleObjects
を使用したマルチスレッド排他処理の動作確認です。
// // 【スレッドで順次処理(順不同)】※Windows7で動作確認済 // (c) 2017 mikan // ※使用にあたっては利用者の自己責任でお願いします。 // ※参考文献 Advaned Windows 改訂第4版 Jeffrey Richter // #include "stdafx.h" #include "windows.h" #define MAX_RUN_THREAD_NUM 32 // 作成するスレッドの数 int gCount; // カウンタ int gNumber[MAX_RUN_THREAD_NUM]; // スレッド番号 char gName[256]; // スレッド名 HANDLE ghEvent; // イベントハンドル // ---------- 状態表示 ---------- void print_status() { int i; printf("%s:", gName); for (i = 0; i < MAX_RUN_THREAD_NUM; i++) { printf("%2d,", gNumber[i]); } printf("count=%2d\n", gCount); } // ---------- スレッド ---------- int Thread(PVOID pvParam) { int *n; // イベントシグナル待ち(30秒でタイムアウト) DWORD dw = WaitForSingleObject(ghEvent, 30 * 1000); if (dw == WAIT_FAILED || dw == WAIT_TIMEOUT) { return -1; } n = (int*)(pvParam); gNumber[gCount] = *n; gCount++; sprintf(gName, "Thread%02d", *n); // 状態表示 print_status(); //Sleep(200); // debug用 // イベントシグナル SetEvent(ghEvent); return 0; } // ---------- 親スレッド ---------- int ThreadCtrl() { int x[MAX_RUN_THREAD_NUM]; int i; DWORD dwThreadId[MAX_RUN_THREAD_NUM]; HANDLE hThread[MAX_RUN_THREAD_NUM]; // 初期化 gCount = 0; memset(gNumber, 0x00, sizeof(gNumber)); memset(gName, 0x00, sizeof(gName)); memset(hThread, 0x00, sizeof(hThread)); for (i = 0; i < MAX_RUN_THREAD_NUM; i++) { x[i] = i+1; } // 自動リセットイベント作成(いずれかのスレッド1つだけが、シグナルを検出) ghEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // 手動リセットイベント作成(全てのスレッドが、同時にシグナルを検出) // ghEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // スレッド作成 for(i=0; i<MAX_RUN_THREAD_NUM; i++) { hThread[i] = CreateThread( NULL, 0, (PTHREAD_START_ROUTINE)Thread, (PVOID)&x[i], 0, &dwThreadId[i]); } // イベントシグナル SetEvent(ghEvent); // 全スレッド終了待ち DWORD dw = WaitForMultipleObjects( MAX_RUN_THREAD_NUM, hThread, TRUE, 50 * 1000); // 50秒でタイムアウト // スレッドハンドルクローズ for (i = 0; i < MAX_RUN_THREAD_NUM; i++) { CloseHandle(hThread[i]); } if (dw == WAIT_FAILED || dw == WAIT_TIMEOUT) { return -1; } return 0; } // ---------- メイン ---------- void main() { int x; HANDLE hThreadCtrl; DWORD dwThreadCtrlId; DWORD dwStart; dwStart = GetTickCount(); printf("開始\n"); // 親スレッド作成 hThreadCtrl = CreateThread( NULL, 0, (PTHREAD_START_ROUTINE)ThreadCtrl, (PVOID)&x, 0, &dwThreadCtrlId); // 親スレッドの終了待ち(60秒でタイムアウト) DWORD dw = WaitForSingleObject(hThreadCtrl, 60 * 1000); // 親スレッドハンドルクローズ CloseHandle(hThreadCtrl); printf("終了\n"); printf("経過時間=%d ms\n", GetTickCount() - dwStart); if (dw == WAIT_FAILED || dw == WAIT_TIMEOUT) { ; } return; }
【実行結果】
※本PGでは各スレッドの起動順序はOSまかせとなります
【手動リセットイベントで全スレッドを同時実行した結果】
※カウンタを正しくインクリメント出来ない可能性あり