スレッドの基礎

スレッドを起動して、メインウインドウとタイトルバーに現在時刻を表示します。
マルチスレッドとは、プロセスを更に細かい単位に区切って(例えば, 計算・入力・描画・ファイル操作等に分割) これを一個の単位として独立して実行する方法です。
今回はメインプログラムでタイトルバーに、スレッドでウインドウの中央に平行処理で現在時刻を表示します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの説明

  1. 新規プロジェクト(Thread)を作成して下さい。
  2. ID_TIMER はタイマーのIDです。
    DATA はスレッドに渡すパラメータの構造体の宣言です。
    DATA Data; でグローバル領域に構造体を確保しています。
    DWORD Thread(LPVOID); はスレッドで起動する関数の宣言です。
        #define     ID_TIMER    (WM_APP + 0)
    
        typedef struct
        {   HWND    hwnd;
            int     end;
        }   DATA,   *PDATA;
        DATA        Data;
    
        // Function-prototypes
        LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
        DWORD   WINAPI      Thread(LPVOID);
        
  3. WinMain() ではサイズを設定してウインドウを表示するだけです。
  4. CALLBACK 関数です。
    スレッドを生成する領域と現在時刻を編集する領域を定義します。
    WM_CREATE: では CreateThread(); でスレッドを生成します。
    メインではタイマを設定してウインドウのタイトルバーに時刻を表示します。
        LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {
            static HANDLE   hThread;
            DWORD           threadID;
            char            *str_org = "現在時刻=%2d時%2d分%2d秒";
            char            str[256];
            SYSTEMTIME      st;
    
            switch(msg)
            {
                case WM_CREATE:
                    Data.hwnd = hWnd;
                    Data.end = 0;
                    hThread = CreateThread(NULL, 0,
                        (LPTHREAD_START_ROUTINE)Thread,
                        (LPVOID)&Data,
                        0, (LPDWORD)&threadID);
                    SetTimer(hWnd,ID_TIMER,100,NULL);
                    break;
        
  5. CALLBACK 関数の続きです。
    WM_TIMER: でウインドウのタイトルバーに現在時刻を表示します。
            case WM_TIMER:
                GetLocalTime(&st);
                wsprintf(str, str_org, st.wHour, st.wMinute, st.wSecond);
                SetWindowText(hWnd,(LPCSTR)str);
                break;
        
  6. マウスの右ボタンがクリックされると MessageBox を表示して処理を5秒間 Sleep します。
    Sleep 中もスレッドは止まらずに動作することを確認して下さい。
            case WM_RBUTTONDOWN:
                MessageBox(NULL,"RBUTTON","Sleep 5000",MB_OK);
                Sleep(5000);
                break;
        
  7. WM_CLOSE: でプログラムを終了します。
    マルチスレッドでは、スレッドの終了を確認してからメインプログラムを終わらせます。
    終了手順を確認するためにメッセージボックスを表示しています。
    タイマを停止して Data.end に1を設定してスレッドが終了するのを待ちます。
    WaitForSingleObject(hThread, INFINITE); が終了を待ち合わせる関数です。
    CloseHandle(hThread) でスレッドを閉じます。
            case WM_CLOSE:
                KillTimer(hWnd, ID_TIMER);
                Data.end = 1;
                WaitForSingleObject(hThread, INFINITE);
                MessageBox(NULL, "スレッド終了成功!", "終了確認", MB_OK);
                if (CloseHandle(hThread) != 0)
                    MessageBox(NULL, "ハンドルクローズ成功!", "終了確認", MB_OK);
                DestroyWindow(hWnd);
                break;
        
  8. Thread で動作する関数です。
    パラメータで渡された構造体のポインタを設定します。
    その他の定義されている領域はメインウインドウに現在時刻を表示するためのものです。
    pData->end がゼロの間、現在時刻を表示し続けます。
        DWORD  WINAPI  Thread(LPVOID param)
        {   PDATA       pData;
            char        *str_org = "現在時刻=%2d時%2d分%2d秒";
            char        str[256];
            SYSTEMTIME  st;
            HDC         hdc;
            RECT        rc;
    
            pData = (PDATA)param;
            while(!pData->end)              //end==0 の間ループ
            {   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;
        }
        

【演習】

  1. プログラムを完成させて下さい。
  2. 描画をしながら Probress Bar を表示 と違ってスレッドでは独立して動作するのでメインを Sleep してもスレッドは動き続けます。
    マウスを右クリックして試してみて下さい。

【参考】

C言語(旧形式)のマルチスレッドは、次の方法で作成します。
  1. コンパイラの設定でコード生成をマルチスレッドにします。
    [プロジェクト] [設定] [C/C++] [コード生成] でランタイムライブラリを [マルチスレッド] にします。
  2. Libcmt.lib, Msvcrt.libをリンクします。
  3. ソースファイルに process.h をインクルードします。
  4. _beginthread(ThreadMain, 0, &val); でスレッドを開始します。
  5. _endthread(); でスレッドを終了します。

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

超初心者のプログラム入門(Win32API C++)