Windows(Native)におけるスレッド処理 - inoueshinichi/Wiki_Windows GitHub Wiki

参考(公式)

参考

WaitSigleObjectが待機できるハンドル(プロセスで一意なオブジェクト)一覧

  • 変更通知
  • コンソール入力
  • イベント
  • メモリ リソース通知
  • Mutex
  • Process
  • Semaphore
  • スレッド
  • 待機可能タイマー

スレッドにイベントループを実装する場合, メッセージキューの作成を待ってから実行する

  • ウィンドウを直接的/間接的に生成する際に使用する待機関数は, WaitSingleObjectではなくMsgWaitForMultiObjectsまたはMsgWaitForMultiObjectsExを使用すること.
  • 直接または間接的にウィンドウを作成する待機関数とコードを呼び出す場合は注意が必要.
  • スレッドがウィンドウを作成する場合は, メッセージを処理する必要がある(イベントループ).
  • メッセージブロードキャストは, システム内のすべてのウィンドウに送信される.
  • タイムアウト間隔のない待機関数を使用するスレッドでは, システムがデッドロックする可能性がある.
// ワーカースレッド関数
unsigned int WINAPI WorkerThreadFunc(void *arg)
{
    HANDLE hThreadInitEvent = (HANDLE)arg;

    MSG uMsg;

    // スレッドキューの作成
    PeekMessage(&uMsg, NULL, 0, 0, PM_NOREMOVE);

    // イベント(False -> True)
    ::SetEvent(hThreadInitEvent);

    while (true)
    {
        if (PeekMessage(&uMsg, NULL, 0, 0, PM_NOREMOVE) > 0)
        {
            if (GetMessage(&uMsg, NULL, 0, 0) > 0)
            {
                ~
             }
             else
             {
                 break; // WM_QUIT
             }
         }
     }

    ::_endthreadex(1234);

    return 0;
}


// メインスレッド側
int main()
{
    HANDLE hThreadInitEvent = ::CreateEvent(NULL, // SECURITY_ATTRIBUTE構造体
                                            TRUE, // リセットのタイプ(True:自動, False:手動)
                                            FALSE, // 初期状態(True:シグナル状態, False:非シグナル状態)
                                            NULL);
    
     // ワーカースレッド作成
    DWORD nThreadId = 0;
    HANDLE hThread = (HANDLE)::_beginthreadex(NULL, // SECURITY_ATTRIBUTE構造体
                                              0, // スタックサイズ(0は呼び出し側と同じサイズ)
                                              &WorkerThreadFunc, // ワーカスレット関数ポインタ
                                              (void*)hThreadInitEvent, // スレッド関数の引数
                                              0, // 作成オプション (0: CREATE_SUSPENDED)
                                              &nThreadId // スレッドID (DWORD)
                                              );

    // スレッドキューの作成待ち
    //::WaitForSingleObject(hThreadInitEvent, INFINIT); // 恐らくこの`WaitForSingleObject`はアンチパターン
    MsgWaitForMultiObjects(~~~); // こっちを使う?
    
    // スレッド初期化イベントの破棄
    ::CloseEvent(hThreadInitEvent);

    // ワーカースレッドへのメッセージの送信
    PostThreadMessage(nThreadId, ~);

    // ~~~~

    // スレッド終了待ち
    ::WaitForSingleObject(hThread, INFINIT); 
    


    // スレッドイベントの破棄
    ::CloseEvent(hThread);

    // ワーカースレッドの終了状態を取得
    DWORD dwExitCode;
    ::GetExitCodeThread(hThread, &dwExitCode);
}