スレッド終了を待つ

マルチスレッドプログラミングでは、一方の処理結果をもう一方で使う時などあるスレッドが終了するのを待ちたい時があります。Win32では、スレッドに限らず様々な「オブジェクト」の状態が変化する(シグナル状態になる)のを待つ関数、WaitForSingleObjectがあるので、今回はこれを使って「他のスレッドの終了を待つスレッド」を作りマルチスレッドにおける他スレッドの終了待機を試してみましょう。

WaitForSingleObject関数

WaitForSingleObject関数は以下の形です。

DWORD WaitForSingkeObject(
      HANDLE  hHandle,
      DWORD   dwMilliseconds);

引数は2つで、それぞれオブジェクトのハンドルと待機するタイムアウト時間(ミリ秒単位)を指定します。また、タイムアウトにINFINITEを指定するとオブジェクトがシグナル状態になるまで待ち続け、0だとオブジェクトの状態を調べた後ですぐに帰ってきます。
今回のスレッド終了を待つ処理では、ハンドルにスレッドを作成した時に返されたスレッドのハンドルを、タイムアウトにINFINITEを指定しましょう。

具体的には、あるスレッド(ハンドルhThread)が終了する(シグナル状態になる) まで待つ処理は以下のようになります。

WaitForSingleObject(hThread,INFINITE); /* スレッド終了まで待つ */

WaitForSingleObjectでは、スレッドだけでなくプロセスやイベント、セマフォなどいろいろな「オブジェクト」がシグナル状態になるのを待つ事ができます。特に、セマフォやミューテックスなどはマルチスレッドで駆動されるプログラムのスレッド間で「同期」をとる際に重要になってくるのでそのうち試してみる事になるかもしれません。

プログラム

今回は、スレッドの作成の時と同様にスレッドを2つ作ります。スレッド1は1000までスレッド2は4000まで数を数え表示して行くスレッドで、先に数えおわるスレッド1がスレッド2の終了を待つようにしました。

スレッドの関数

  DWORD WINAPI fnThread1(LPVOID lpV) { /* スレッド1 */

      int i;
      char lpszStr[64];

      i=0; /* カウンタ変数クリア */

      while (i<1000) { /* 1000までカウント */

          i++; /* カウンタを一つ増やす */

          wsprintf(lpszStr,"Thread1 %8d",i);	
          SetWindowText(hwLabel1,lpszStr); /* カウンタの数を表示 */

          Sleep(1); /* ウエイト */

      }

      SetWindowText(hwLabel1,"Thread1 Waiting"); /* 待機メッセージを表示 */

      WaitForSingleObject(hThread2,INFINITE); /* スレッド2が終わるまで待つ */

      SetWindowText(hwLabel1,"Thread1 Stop"); /* 終了メッセージを表示 */

      return 0;

  }

  DWORD WINAPI fnThread2(LPVOID lpV) { /* スレッド2 */

      int i;
      char lpszStr[64];

      i=0;

      while (i<4000) {

          i++;

          wsprintf(lpszStr,"Thread2 %8d",i);	
          SetWindowText(hwLabel2,lpszStr);

          Sleep(1); /* ウエイト */

      }

      return 0;

  }

プログラムは、Startボタンがクリックされるとスレッド1・2を作り、上の関数を実行します。


  hThread1=CreateThread(NULL,0,fnThread1,0,0,&d); /* スレッド作成 */
  hThread2=CreateThread(NULL,0,fnThread2,0,0,&d);
プログラムソース表示

ただし、今回のプログラムではすでにスレッドが実行中かどうかのテストをしていません。スレッド実行中でも新たなスレッドを作成できてしまいますから、スレッド実行中にStartボタンをクリックしないでください。