※ ChatGPTを利用し、要約された質問です(原文:スレッドの安全な終了のさせ方)
スレッドの安全な終了のさせ方
スレッドの安全な終了のさせ方
メインスレッドにてCreateThread命令を使い、あるサブスレッドを作りました。
このサブスレッドは内部でmallocを使い動的に配列領域を確保して
その配列領域をforループ等で「かなり時間の掛かる処理」として繰り返し
アクセスしています。
ループが終了した時に「free」を実行してmalloc領域を開放しています。
アプリ終了時にメインスレッドからこのサブスレッドを終了させるのに
メインウインドウにWM_DESTROYメッセージが送られた時、これまで単に
そこで「CloseHandle(hSubThread);」とだけ書いていたのですが、
もしかしたらこれでは場合によっては(サブスレッドがループ処理中だったら)
malloc領域が開放されずにリークしてしまうのではないかと思いました。
そこでイベントオブジェクトを使い、サブスレッドがループ処理中の
時には非シグナル状態にして、ループが終了しfreeで領域を開放した後
シグナル状態にするということにして、メインスレッドはそれを
WaitForSingleObjectで待つという構造にしました。
ところが「メインスレッドに待ちを作るな」という言葉通り、これでは
上手く行きませんでした。サブスレッドはその時間の掛かる処理の
最中でSendMassage等でメインスレッドの処理を促すような命令を
(例えばその処理の進捗状況を表示するなど)を幾つも行っていたので、
もしWaitFor~でメインを待たせると「サブスレッドの処理も進まなくなり
結果両方がロックして動かなくなってしまう」という悲しい状況に
嵌ってしまうのです。
SendMessageを徹底的に無くすということも考えたのですが、
(例えばPostMessageに書き換えるなどもやってみたのですが、これは
全く意図した動作をしてくれない場合もあり)、別の方法では
どうしても代替できないケースもあって、全て消すというのは
現実的ではないのかもと。。
このようなサブスレッドを安全に終了させるにはどうしたら良いでしょうか?
あるいは単にデストロイ時にCloseHandleとするだけでも良いのでしょうか?
お礼
>つまりサブスレッドがメインスレッドとなんらかのやりとりをしたいなら、 >この時点でメイン側はWaitForSingleObjectで待ってはいけません。 >1. Main -> Subに終了前準備しろと通知 >2. Sub -> Mainに終了前準備完了を通知 >3. Main -> Subに終了しろと通知 >4. MainはSubが終了するのをWaitForSingleObjectで待つ。 解説ありがとうございます。 「段階に分けて」終了処理を行うんですね。 それを受けてメインスレッドのコールバックプロシージャのイベント処理を 書き直しました。 まず「1. Main -> Subに終了前準備しろと通知」 をWM_DESTROYイベントで行っては、そのままメインスレッドが サブの終了を待てずに終わってしまうので その一段階前にWM_CLOSEイベントでこの通知を行い、 この通知を受け取ったサブはスレッドのループを抜けて メインへ「PostMessage」でExit準備完了を通知 (ここでSendMessageを使うと元も子もないので)。 (MY_WM_SUBTHREAD_READY_TO_EXITをメインへポスト)。 メインでMY_WM_SUBTHREAD_READY_TO_EXITを受け取るとそこで WaitForSingleObject(hSubThread,INFINITE); でスレッド終了を待つ。 スレッドが終了したのち、スレッドのハンドルをクローズし DestroyWindowで終了する。 これで無事終了させることができました。 それにしても、段階に分けて終了処理を行うというのはとても 賢明な方法ですね。 教えていただいて、"なるほど"、と初めて気が付きました。 お陰様でプログラムを安心して終了させられそうです。 sha-girlさん、回答ありがとうございました。またよろしくお願いします。 ---------(code)----------- case WM_CLOSE: MessageBox(hWnd,"サブスレッドEXITメッセージポスト。","終了処理",MB_OK); PostThreadMessage(subThread_ID,MY_TM_ABORT_THREAD,0,0);//スレッド中断メッセージのポスト return TRUE; case MY_WM_SUBTHREAD_READY_TO_EXIT: MessageBox(hWnd,"サブスレッドEXIT準備完了を受信。","終了処理",MB_OK); WaitForSingleObject(hSubThread,INFINITE); CloseHandle(hSubThread); MessageBox(hWnd,"スレッド終了処理が完了しました。","終了処理",MB_OK); DestroyWindow(hWnd); return TRUE; ---------(code end)-----------