WaitForSingleObject関数の第1引数にスレッドハンドル第2引数にINFINITEを 指定するとスレッドが終了するまで眠らせることができます。
では、早速例題を見てみましょう。
何の変哲もないウィンドウです。クライアント領域の中央に
現在時刻が表示されます。
これは、いつもと同じですね。// mult05.cpp #define STRICT #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); DWORD Thread(LPVOID); typedef struct{ HWND hwnd; BOOL bEnd; }PARAM, *PPARAM; char szClassName[] = "mult05"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }
いつもと同じです。//ウィンドウ・クラスの登録 BOOL InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); }
これも、いつもと同じです。//ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるマルチスレッド",//タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
WM_CREATEでスレッドを作ります。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HANDLE hThread; DWORD threadID; static PARAM data; switch (msg) { case WM_CREATE: data.hwnd = hWnd; data.bEnd = FALSE; hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Thread, (LPVOID)&data, 0, (LPDWORD)&threadID); break; case WM_CLOSE: id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか", (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { data.bEnd = TRUE; WaitForSingleObject(hThread, INFINITE); MessageBox(NULL, "スレッド終了", "成功!", MB_OK); if(CloseHandle(hThread) != 0) MessageBox(NULL, "ハンドルクローズ成功", "成功!", MB_OK); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }
WM_CLOSEが来て、終了しても良いとなったら、
data.bEndをTRUEにしてスレッド内のループを終了させ
スレッドを終了させます。
このあと、WaitForSingleObject関数を実行すると 実際にスレッドが終了するまで次のステップに進みません。 スレッドが終了したのがわかったら、メッセージボックスを 出してスレッドが終了した旨ユーザーに知らせます。
次に、スレッドハンドルをクローズして親ウィンドウを終了させます。
スレッド関数です。DrawText関数については第5章に 簡単な解説があるので参考にしてください。DWORD Thread(LPVOID param) { PPARAM pData; HDC hdc; RECT rc; char *str_org = "現在時刻=%2d時%2d分%2d秒"; char str[256]; SYSTEMTIME st; pData = (PPARAM)param; while(!pData->bEnd) { GetLocalTime(&st); wsprintf(str, str_org, st.wHour, st.wMinute, st.wSecond); hdc = GetDC(pData->hwnd); GetClientRect(pData->hwnd, &rc); DrawText(hdc, str, lstrlen(str), &rc, DT_SINGLELINE | DT_VCENTER | DT_CENTER); ReleaseDC(pData->hwnd, hdc); Sleep(300); } return 0L; }
今回は、簡単でした。マルチスレッドに関してはまだまだ、やることがたくさんありますが、
少しずつやっていくことにします。(急がば回れ)
Update Nov/30/1997 By Y.Kumei