• ベストアンサー

スレッドの終了を知りたい(WindowsAPI)

CreateThread()で作成したスレッドの終了を知りたい (具体的には、スレッドが終了するまで待機したい)のですが、 うまくいかず困っています。WindowsAPIに関する本やネットで調べた ところ、WaitForSingleObject()が適用できると考え、 以下のようなプログラムを作成したのですが、 元のスレッドがWaitForSingleObject()のところで 止まると同時に、CreateThread()で作成されたThread_1()も 止まってしまいます。アドバイスいただけますでしょうか。 ----プログラム(該当部分)ここから---- DWORD Thread_1(LPVOID param) {  int i;  char buff[128];  /* iが99のときのみ終了してよい */  while(g_iFlg == 1)  {   for(i = 0; i < 100; i++)   {    Sleep(100);    wsprintf(buff, "%d", i);    SetDlgItemText((HWND)param, IDC_STATIC_1, buff);   }  }  ExitThread(0);  return 0; } BOOL CALLBACK Proc_2(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {  switch(uMsg)  {   case WM_INITDIALOG:    g_iFlg = 1;    g_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread_1, (LPVOID)hDlg, 0, &g_dwThread);    return TRUE;   case WM_COMMAND:    switch(LOWORD(wParam))    {     case IDC_BUTTON_CANCEL:     case IDCANCEL:      g_iFlg = 0;      WaitForSingleObject(g_hThread, INFINITE);      CloseHandle(g_hThread);      EndDialog(hDlg, 0);      return TRUE;    }  }  return FALSE; } ----プログラム(該当部分)ここまで----

質問者が選んだベストアンサー

  • ベストアンサー
  • itohh
  • ベストアンサー率45% (210/459)
回答No.2

こんにちは。itohhといいます。 このプログラムは。 (1)ウィンドウ(ダイアログ)は1つ。 (2)テキストボックスに子スレッドでカウンタを自動表示する。 (3)「キャンセル」ボタンを押下したとき、(2)の処理が終わるのを待ってから    ダイアログを終了する。 ということでしょうか? たぶん、「キャンセル」ボタンを押下した段階で子プロセスの >SetDlgItemText((HWND)param, IDC_STATIC_1, buff); で止まってしまっているのでしょう。 >SetDlgItemText((HWND)param, IDC_STATIC_1, buff); は、結局、メッセージをダイアログに投げていることになりますから(SendMessage) 他のメッセージ処理が終わるまで(この場合、「WM_COMMAND」-「IDCANCEL」) 「SetDlgItemText」のメッセージ処理が始まることはありません。

kaz99
質問者

お礼

こんにちは。アドバイスありがとうございます。 > このプログラムは。 > (中略) > ということでしょうか? ダイアログは2つです。いわゆる「メイン」および、 「実行中」(ここではカウントしているもの)です。 そして実際には単にカウントするだけではなく、 ある処理を行うのですが、処理進捗状況を示すために、 ダイアログ上のスタティックテキストにカウンタを 表示しているのです。 とにかく、IDCANCELの処理がWaitForSingleObject()のために終了しないので、 SetDlgItemText()によるメッセージの処理がキューに止められてしまい(実行されない)、 Thread_1()も止まってしまうということですね。 う~ん、WaitForSingleObject()を1行記述するだけで うまくいけると考えたんですが・・・残念です。

その他の回答 (4)

  • itohh
  • ベストアンサー率45% (210/459)
回答No.5

こんにちは。itohhといいます。 #4のかたの方法だとカウンタが更新表示されないのでは? (喧嘩を売っているわけではないのですが、お気を悪くされたら、すみません。) 解決策として2つの案を。 (1)カウンタを表示するエディットボックスを別ダイアログにする。    枠なしのダイアログにエディットボックスを貼り付けて見ては如何でしょうか? (2)WaitForSingleObjectで待機するところを別スレッドにする。    「キャンセル」ボタンを押下したとき、別スレッドを立ち上げてそちらで待機する。    WaitForSingleObjectが帰ってきたら「WM_COLSE」メッセージをPostMessageする。 といった案は如何でしょうか。 (試していないのであまり自信はないのですが...)

kaz99
質問者

お礼

こんにちは。アドバイスありがとうございます。 こういう方法もありますか・・・。 No.3のところに書きました通り、メッセージの やりとりを行うようにしたのですが、 今後のために、上記方法も覚えておこうと思います。 ありがとうございました。 ~~~~~ ただ、実を言いますと、今のやり方ではちょっと不安があるのです。 メッセージをポストしたあと、実際にスレッドが終了する前に 実行がもう1つのスレッド(スレッド終了のメッセージを受ける方)に 移ってしまった場合、まだ実際にはThread_1()のスレッドが 終了していないにも関わらずスレッド終了のメッセージを受け、 CloseHandle()等のスレッド終了の処理が行われてしまう可能性が あるということです。 とりあえず、現時点では当初の問題はクリアできたので いったん締め切りたいと思います。 みなさまありがとうございました。

  • akinori_s
  • ベストアンサー率60% (21/35)
回答No.4

今までの回答のようにSetDlgItemTextでデッドロックが起きてしまいますね。 本来ですとPostMessage系でスレッド終了時にメッセージを送信すれば回避 できますが下記のような感じでも回避できると思います。(多分...) 1.SetDlgItemTextをSendMessageTimeoutを使用する。  (送るメッセージはWM_SETTEXT) 2.上記メッセージを送信する前に毎回g_iFlgをチェックする。 でわでわ

kaz99
質問者

お礼

ご回答ありがとうございます。 なるほど、こういう方法もあるのですね。 実際にはNo.3のところに書きましたように、 メッセージをポストするように変更してしまったのですが、 上記方法も今後のために覚えておこうと思います。 ありがとうございますた。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.3

>WaitForSingleObject()1行記述するだけで >実現できると簡潔でよかったんですが・・・ WaitForSingleObjectは、あくまでも引数に指定したオブジェクトの状態が変化するまで処理を停止する関数です。 今回の場合、ウィンドウを持つスレッド自体の動きは停止してはいけないのでWaitForSingleObjectは使えません。 ”待機したい”という意味が、”プログラムを停止してスレッドの終了を待ちたい”というのでしたらWaitForSingleObjectを使うのですけどね。

kaz99
質問者

お礼

アドバイスありがとうございます。 なるほど。 結局、WaitForSingleObject()で待つことをやめ、 Thread_1()のExitThread()の直前でメッセージを投げ、 そのメッセージを受けてCloseHandle()、EndDialog()を 行うようにしたら、うまくいきました。 ありがとうございました。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

スレッドの作成元がウィンドウを持っているのであれば、 PostMessage()やPostThreadMessage()で、 スレッドの終了直前に任意のメッセージを投げて、通知してあげればOKです。

kaz99
質問者

お礼

アドバイスありがとうございます。 やはりメッセージで通知するしかないですか・・・ WaitForSingleObject()1行記述するだけで 実現できると簡潔でよかったんですが・・・