• ベストアンサー

特定のスレッドの破棄

Win32 APIを使っています。 ソートの勉強の為に 右クリックでシャッフル、左クリックでソートするプログラムを作りました。 ソートをスレッドで行なっています。 ソート中に右クリックを押すとシャッフルと同時にスレッドを破棄したいと思ったのですが CreateThreadで作った特定のスレッドを破棄するにはどうしたらよいでしょうか? GetExitCodeThreadとExitThreadを使って破棄すると思い 試してみたらプログラム自体が閉じてしまいました。 タスクマネージャで確認したらプログラム自体はあってウィンドウは表示されてない状態になりました。

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

  • ベストアンサー
  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.2

>具体的にCreateEvent()、SetEvent()、WaitForSingleObject() >などをどこに置くかがわからなかったので教えて欲しいです。 キーワードで検索して使用例とか探してみた方がいいのですが…… とりあえず、猫でも…で下記でしょうかね。 http://www.kumei.ne.jp/c_lang/intro2/no_103.htm >WaitForSingleObject()をSleepの代わりに使って >シグナル状態のときはSetEvent()を呼び出してスレッドに終了を要求するのでしょうか? 違います。 ・メインスレッド側 M1.メインスレッド側でCreateEvent()でイベントを作成しておきます。(非シグナル状態で)  ハンドルは保持できるようにしておく必要があります。(グローバル変数でもプロシージャ内のstatic変数でもいずれかの方法で) M2.メインスレッドからワーカースレッド(例としてシャッフルスレッド)を起動します。  ワーカースレッド起動後はメインスレッドは通常の処理に戻ります。 M3.メインスレッド側でワーカースレッドを終了したいタイミングでM1で作成したイベントをSetEvent()でシグナル状態にします。 ・ワーカースレッド側 W1.ワーカースレッドは開始時にOpenEvent()でM1.で作成したイベントのハンドルを取得します。(イベントに名前を付けておく必要はありますが)  上記の猫でも…ではOpenEvent()はしていません。イベントハンドルをグローバル変数にしているから…ですが。  排他処理の関係でハンドルがおかしくなる場合があるかも知れませんのでグローバル変数使う場合はご注意を。 W2.ワーカースレッドのループ内でWaitForSingleObject()でイベントの状態を確認します。  第2引数に適当な値を入れてSleep()代わりに使うのもいいですし、0を指定してイベントの状態を確認するだけでもいいでしょう。 W3.WaitForSingleObject()の戻り値がWAIT_OBJECT_0の場合、メインスレッド側でスレッドの終了要求がされた(M3でのSetEvent()でシグナル状態)ということで、ワーカースレッドのループを抜けます。 W4.W1でOpenEvent()したハンドルを閉じて、他の後始末をした後でreturnします。  またはExitThread()します。 ざっくりこんな感じ…でしょうかね。 イベントハンドルの保持には気をつける必要があるでしょうけど。 ちなみに、同じワーカースレッドを複数回呼ぶ可能性があるのならば、W4でイベントハンドルを閉じる前にResetEvent()で非シグナル状態にしておく必要があるでしょう。 あるいは…W1でOpenEvent()した時にResetEvent()を実施か、M2でワーカースレッド呼び出す前にResetEvent()を実施。 # CreateEvent()時に第2引数で自動リセットに設定したら…ResetEvent()は不要ですかね。試したコトないですけど。 デッドロックにはご注意を。 # たとえば、M2で通常の処理に戻った時にワーカースレッドのハンドルで終了を待つ…とか。 # ワーカースレッドが時間がたてば終了するなら問題はないですが、外部から終了の契機を与えるまで終わらないタイプだと操作出来なくなってしまいますから。 なんというか、既に「ソートの勉強」ではなくなってますけども。

cern5100
質問者

お礼

詳しくありがとうございます。 思い通りのプログラムができました。 大変勉強になりました。

その他の回答 (1)

  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.1

普通は、スレッド側に「安全に終了する為の仕掛け」を入れ込んでおきます。 たとえば、イベントで通知するようにして、スレッド側は定期的(ループの中とか)にWaitForSingleObject()等でイベントの状態を確認します。 # 状況によってはWaitForMultipleObject()で。 UIスレッドからはSetEvent()などでスレッド側に終了を要求する。 というような流れになります。 # スレッドが終了したかどうか…をCreateThread()で作成した時のハンドルなどで判定する。 # ちなみに、Cランタイムとか使う場合はCreateThread()ではなく_beginthread()などを使います。 スレッド側に安全に終了する仕掛けを入れていない場合は、TerminateThread()で無理矢理殺すことになるでしょう。 リソースリークとか発生する可能性がありますのでご注意を。 >ExitThreadを使って破棄すると思い >試してみたらプログラム自体が閉じてしまいました。 「現在実行しているスレッド」を終了するものです。 UIスレッドで実行したら…ウィンドウが破棄されたように見えるかもしれませんね。 で、他のスレッドが実行中なのでスレッド終了までプロセスが残っている(タスクマネージャに残っている)のでしょう。 # そのままゾンビと化す場合もありますかねぇ……。 その他、同期処理も必要ですのでその辺りには注意が必要です。 # 左クリックでソート実行中にもう一度左クリックするとどうなりますか? # ダブルクリック判定されない程度の早さでクリックし続けるとどうなりますか?とか。

cern5100
質問者

補足

回答ありがとうございます。 そういう風な使い方をするんですね。 Windowsゲームプログラミングという本を参考にしていましたが SetEvent()やTerminateThread()などは載っていなくて スレッドの破棄ではななく停止しかできなかったので困っていました。 ExitThread()は現在実行しているスレッドなんですね。 同期処理はミューテックスを使ってやっています。 具体的にCreateEvent()、SetEvent()、WaitForSingleObject() などをどこに置くかがわからなかったので教えて欲しいです。 WaitForSingleObject()をSleepの代わりに使って シグナル状態のときはSetEvent()を呼び出してスレッドに終了を要求するのでしょうか? ただ>>UIスレッドからはSetEvent()などでスレッド側に終了を要求する。 というのを見ると違いますかね。 これはSetEvent()の中でどうスレッドに終了を要求するのでしょうか? TerminateThread()ではまた同じ問題になってしまいますし・・・ 理解がまだできてない部分が多いのでお願いします。

関連するQ&A