• ベストアンサー

特定のスレッドの破棄

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

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

  • ベストアンサー
  • Wr5
  • ベストアンサー率53% (2177/4070)
回答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% (2177/4070)
回答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

  • スレッドの廃棄について

    ウインドウ上のボタンを押すとあるスレッドがスタートするような プログラムがあるとします。 ボタンのクリックイベントプロシージャ内で 以下のように書いてスレッドをスタートさせることにしたのですが、 Sub MainWnd_CommandButton1_Click() 'スレッドのスタート hThread1=CreateThread(ByVal 0,0,AddressOf(MainOperation),0,0,VarPtr(thread1_ID)) End Sub このままではボタンがクリックされるたびに次々新しくスレッドが 生成されてしまい収拾がつかなくなるのでは?と思います。 基本的に一つのスレッドのみを存在させたいので、 CreateThreadの直前に「CloseHandle(hThread1)」と書こうかとも 思ったのですが、仮にスレッドが存在して無い場合、その場合は 無効なハンドルをクローズすることになりそうで何だか不都合が ありそうです。 スレッドの存在を調べて、あれば安全に廃棄して新しいものをスタート させる、といったことはどのように実装するべきでしょうか? ActiveBasicを使っていますが、教えて頂く際には CやVBでも構いません。

  • スレッドの終了を知りたい(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; } ----プログラム(該当部分)ここまで----

  • マウスの左クリックが反応しない

    マウスの右クリックには反応あり、左クリックのみ無反応です。別のマウスに変えても同じです。 他の人の回答に 『Ctrlキー+Altキー+Deleteキーの同時押しでタスクマネージャーを起動します。 (起動したら、「ファイル」→「新しいタスクの実行」の順にクリック』 とありましたが タスクマネージャー他4つ出てきて 選択しても左クリック出来ないので 起動出来ません。 少し前まで 左の反応が遅かったり変だとは、思ってましたが 全く無反応になりました ※OKWAVEより補足:「富士通FMV」についての質問です。

  • マルチスレッドでブレイクポイントするとフリーズする

    C++/CLI .Net2008 windowsフォームアプリケーション 二つのスレッドが同時に動いているマルチスレッドプログラムを作成しています。 デバッグでブレイクポイントを張って途中で止めたいのですが、止めてすぐもしくはF10で2,3行進めるとフリーズしてアプリが動かなくなってしまいます。他のoutlook等も動かせず、タスクマネージャも開かないため、画面下のウィンドウを右クリック、閉じるを5~10分くらいかけて行って終了させています。たまにVisualStudio自体もフリーズして落ちることがあります。 ブレイクポイントで止めなければフリーズはしません。 プログラムの構成としては、 片方は外部装置からリアルタイムでデータを受信し、判別した結果を出力するスレッドと、その判別結果を元に状態を遷移させるスレッドです。 また、状態によってはタイマーを設けている箇所があり、タイマー処理もスレッドで行っています。 ブレイク張らずに実行した時におかしい動作をしている箇所があるので1行ずつ見たいのですが、マルチスレッド環境ではフリーズするものなのでしょうか?

  • タスクマネージャを起動したい

    タスクバーから右クリックしても何の反応もしません ヘルプから「windowsタスクマネージャを使用する」でも 「このプログラムを起動できませんでした」とでます 如何したらよいでしょうか ([Ctrl][Alt][Del]を同時に押しても反応ナシなのは関係ありますか?)

  • タスクマネジャー

    タスクマネジャーが出てこない タスクバーを右クリックしてタスクマネジャーを選択しても表示されない Ctrl押しながらのショートカットでも表示されない ウイルスか何かによってプログラムが消去されたんですかね? どうしたら表示されますか?

  • これってスパイウェアでしょうか?

    お世話になります。 すいません質問させて下さい。 タスクバーを右クリック→タスクマネージャを左クリック→プロセスを左クリック→でユーザー名がownerになっている場合、もしくは タスクバーを右クリック→タスクマネージャを左クリック→ユーザーを左クリック→でユーザー名がownerになっている場合はスパイウエアに侵されているかもしれない。と聞きましたが本当でしょうか? そしてもしスパイウエアに侵されている場合どう対策をとればよいでしょうか?  一応当方のパソコンにはノートンウイルスバスター、spybot,ad-awareが入っております。定期的にウイルスチェックもしております。  当方パソコンにおいてまるっきりの無知なモノで、初歩的な質問かもしれませんがどうか回答よろしくお願いしますm(__)m

  • 特定のスタートアップを無効にしたい

    特定のスタートアップを無効にするか削除したいのですが、どうすればいいでしょうか? スタート→すべてのプログラム→スタートアップから右クリックで「削除」を選択すると、アイコンののみが削除されるだけで、プログラムは削除されないと出ます。 そのため、コントロールパネルの「プログラムの追加と削除」で行ってくださいと出るのですが、そこではそのソフト自体を削除することしかできないみたいです。 ちなみに消したいスタートアップは、2ちゃんねるの禁断の壺というものです。 どなたかアドバイスをお願いします。

  • ideapad100でマウスクリックが動かない

    ideapad100の右クリック、左クリックが動かなくなりました。 切っ掛けは不明ですが、先週何らかの更新が動いた後からのような気がします。 マウスの故障かと思いましたが、タッチパッドも同じでした。 ・タッチパッドもマウスも同じ現象 ・スクロールは出来るが右クリック、左クリックが出来ない ・電源オプションの高速スタートアップは無効 ・なぜかタスクマネージャを立ち上げるとクリックが出来る ・タスクマネージャでメモリー使用率が高いため8GBに交換したが同じ現象 よろしくお願いします。 ※OKWAVEより補足:「Lenovo:ノートブック (IdeaPad・Lenovo等)」についての質問です。

  • タスクマネージャーが起動しない

    タスクマネージャーをCtrl + ALT +DELやタスクバーの右クリックから起動しようとすると、 ユーザー 状態 アクティブ などの表記が出てきて、切断かログオフのどちらかしか クリックできない画面に移行してしまいます。 通常のタスクマネジャーを出したいのですが どうすればよいでしょうか。  通常のタスクマネージャーというのは、実行中のプログラムの リストが出てきたり、それを終了させたりできる画面のことを意味しています。 どうぞよろしくおねがいします。 OSはXPです。