VC++スレッドの正しい終了のさせかた

このQ&Aのポイント
  • VC++6.0でスレッドを終了させる方法について説明します。
  • スレッドが正しく終了されていない可能性があるため、スレッドの終了方法について質問があります。
  • AfxBeginThreadでスレッドを起動し、m_bAutoDelete = TRUEにしていますが、スレッドの終了時に問題が発生しているようです。
回答を見る
  • ベストアンサー

VC++スレッドの正しい終了のさせかた

VC++6.0にてAfxBeginThreadで m_bAutoDelete = TRUEにてスレッドをおこしております。 この終了時に制御関数のwhileループを脱する様にし、 正常にスレッドを終了させているつもりです。 この後、再度(アプリは継続して起動したまま) AfxBeginThreadにて全く同じ処理で再開すると、 なぜか、前のスレッドが未だ動作しているかのごとく 制御関数内のTRACEが2重に出力されます。 再度、停止し、またスレッド起動すると、 今度は3重になったかの様な動作をします。 スレッドが正しく終了されていないのでは?と思った現象として、 1回起動時にアプリを終了させると正常終了しますが、 2回起動以上は必ずスレッドのメモリーリークが出ます。 メモリーリーク個所はAfxBeginThreadでした。 制御関数内で必要ないとは思いましたが、終了時に AfxEndThreadを使用しましたが現象は同じでした。 そこで質問です。 1)この現象は、スレッドが正常に終了されていない事に起因しているのでしょうか? 2)スレッドを正しく終了させるにはどうすればいいのでしょうか? 当方、制御関数がループを抜け、さらにm_bAutoDelete = TRUEであれば オブジェクトも自動的に破棄されると思っていたのですが。。。 以上、よろしくお願いします。

  • Vargas
  • お礼率85% (174/204)

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

  • ベストアンサー
回答No.2

 こんばんは。  AfxEndThread()で起動した物は「m_pThread->PostThreadMessage(WM_QUIT, 0, 0)」で終了させないといけないらしいです。  http://hp.vector.co.jp/authors/VA014436/prg_memo/windows/vctips/038.html  試してみましたが、此れで一応綺麗に終るようです。 CWinThread* m_pThread; bool m_bSuspend = false; static UINT Proc(LPVOID pData) { MSG msg; CDlg* p = static_cast<CDlg*>(pData); p->SetDlgItemText(IDC_EDIT1, "START"); while(::GetMessage(&msg, NULL, 0, 0)) { switch(msg.message) { //case WM_QUIT:break; default:; } } //ココまで来ないといけない p->SetDlgItemText(IDC_EDIT1, "END"); return 0; } void CDlg::OnSwitch() { // TODO: この位置にその他の検証用のコードを追加してください //初めての作成 if(!m_pThread) { m_pThread = ::AfxBeginThread(&::Proc, this); } else { //寝ているスレッドを叩き起こす if(m_bSuspend) { SetDlgItemText(IDC_EDIT1, "RESUME"); m_pThread->ResumeThread(); } //寝かす else { SetDlgItemText(IDC_EDIT1, "SUSPEND"); m_pThread->SuspendThread(); } m_bSuspend ^= true; } } void CDlg::OnExit() { // TODO: この位置に特別な後処理を追加してください。 if(m_pThread) { //寝ているスレッドを叩き起こす(寝ていなければ無視される) m_pThread->ResumeThread(); m_pThread->PostThreadMessage(WM_QUIT, 0, 0); m_pThread = 0; } }

Vargas
質問者

お礼

回答ありがとうございました。 原因は、制御関数内のwhile文を抜ける前に次のスレッドが起動されて いる様で、そこで前のスレッドが正しく終了していませんでした。 スレッド停止命令後にwaitforsingleobjectにて待機させ、制御関数内のwhile文を抜けた後にseteventする処理手順を踏んだらOKでした。 ありがとうございました。 あと、PostThreadMessage(WM_QUIT, 0, 0)も試してみました。ばっちりでした。勉強になりました。

その他の回答 (1)

  • arain
  • ベストアンサー率27% (292/1049)
回答No.1

>1)この現象は、スレッドが正常に終了されていない事に起因しているのでしょうか? はい。 >2)スレッドを正しく終了させるにはどうすればいいのでしょうか? >当方、制御関数がループを抜け、さらにm_bAutoDelete = TRUEであれば >オブジェクトも自動的に破棄されると思っていたのですが。。。 「オブジェクトの破棄」と「オブジェクト内で生成したオブシェクトの破棄」はイコールではありません。 AfxBeginThreadで生成しているスレッド内で作成、もしくは実行しているオブジェクトの終了ミスか、 終了処理は行っていても、スレッド終了時までにその処理が間に合わず残っている可能性はあります。

Vargas
質問者

お礼

回答ありがとうございました。 原因は、制御関数内のwhile文を抜ける前に次のスレッドが起動されて いる様で、そこで前のスレッドが正しく終了していませんでした。 スレッド停止命令後にwaitforsingleobjectにて待機させ、制御関数内のwhile文を抜けた後にseteventする処理手順を踏んだらOKでした。 ありがとうございました。

関連するQ&A

  • スレッドの終了はどうやるんですか?

    VCでスレッドの終了をしたいと考えてます。 自分自身のスレッドを終了するときは、AfxEndThread関数を使うようですが、動作中のスレッドを外から命令して終了させるときはどうすれば良いのか分からないです。教えていただけないでしょうか?

  • C#でスレッドを終了させるには、どのようにすれば良いでしょうか。

    C#でスレッドを終了させるには、どのようにすれば良いでしょうか。 http://msdn.microsoft.com/ja-jp/library/7a2f3ay4(VS.80).aspx のように、スレッドのループ条件をfalseにする関数を作りました。 ボタンを押したときにこの関数を呼び出すようにしたら、スレッドは終了しました。 しかし、アプリケーションが終了したらスレッドも終了するようにしたいと思います。 この関数をどこで呼び出すのが一般的でしょうか? よろしくお願いします。

  • スレッドの安全な終了のさせ方

    スレッドの安全な終了のさせ方  メインスレッドにてCreateThread命令を使い、あるサブスレッドを作りました。 このサブスレッドは内部でmallocを使い動的に配列領域を確保して その配列領域をforループ等で「かなり時間の掛かる処理」として繰り返し アクセスしています。 ループが終了した時に「free」を実行してmalloc領域を開放しています。 アプリ終了時にメインスレッドからこのサブスレッドを終了させるのに メインウインドウにWM_DESTROYメッセージが送られた時、これまで単に そこで「CloseHandle(hSubThread);」とだけ書いていたのですが、 もしかしたらこれでは場合によっては(サブスレッドがループ処理中だったら) malloc領域が開放されずにリークしてしまうのではないかと思いました。  そこでイベントオブジェクトを使い、サブスレッドがループ処理中の 時には非シグナル状態にして、ループが終了しfreeで領域を開放した後 シグナル状態にするということにして、メインスレッドはそれを WaitForSingleObjectで待つという構造にしました。 ところが「メインスレッドに待ちを作るな」という言葉通り、これでは 上手く行きませんでした。サブスレッドはその時間の掛かる処理の 最中でSendMassage等でメインスレッドの処理を促すような命令を (例えばその処理の進捗状況を表示するなど)を幾つも行っていたので、 もしWaitFor~でメインを待たせると「サブスレッドの処理も進まなくなり 結果両方がロックして動かなくなってしまう」という悲しい状況に 嵌ってしまうのです。 SendMessageを徹底的に無くすということも考えたのですが、 (例えばPostMessageに書き換えるなどもやってみたのですが、これは 全く意図した動作をしてくれない場合もあり)、別の方法では どうしても代替できないケースもあって、全て消すというのは 現実的ではないのかもと。。  このようなサブスレッドを安全に終了させるにはどうしたら良いでしょうか? あるいは単にデストロイ時にCloseHandleとするだけでも良いのでしょうか?

  • スレッドの終了の仕方

    こんばんわ 今スレッドを使ったプログラムを組んでいるのですが、_beginthreadexで起動したスレッド(無限ループ)二つをある条件の時にmainで終了させたいのですが、_endthreadでは特定のスレッドを終了させるようなパラメータが無いみたいなのでどうしていいかわかりません。CloseHandleだけでも終了させることができるのでしょうか??何かいい方法は無いでしょうか? windowsプログラム初心者なので分かりにくい質問で申し訳ないです。

  • マルチスレッド:スレッドの終了を検知する(Ruby)

    2つ以上のスレッドを生成・動作させ、それらが終了した時点で、メインに処理を移すといったことをRubyでしたいと思っています。 (スレッドが1つならば、メインをstopさせておき、スレッドの終了時に例外処理などを使ってrunさせる方法は思いつくのですが。。) 一つ考えたのは・・・ カウンタ変数をつくり、一つのスレッドが終了したらその値を増やす。 メインではwhileループによってその値を常に数えて、全スレッドの終了を把握する。 ただ無駄にwhileループを回してしまいます。。 一般的な効率の良い手段等あるのでしょうか?

  • [VC++] AfxBeginThreadで生成したスレッドの監視方法について

    お世話になります。 VC++でスレッドプログラムを作っています。 AfxBeginThreadでワーカースレッドを作成し、その中でダイアログを表示する プログラムです。 問題は、ワーカースレッドがある処理状態に至ったことを メインスレッドで検知したいのですが、それがうまく いかないということです。 コードの概略をしめします。 <メインスレッド側> void CTestApp::OnTest() {   CTestDlg dlg;   dlg.IsContinue = FALSE;   pThread = AfxBeginThread(TestDlg::Thread, (void*)&dlg);   while (!dlg.IsContinue) { // <----問題:このループ処理を抜けれない!    Sleep(0);   } } <ワーカースレッド側> UINT TestDlg::Thread(LPVOID pParam){   TestDlg* pDlg = (TestDlg*)pParam;   pDlg->Create(TestDlg::IDD);   pDlg->ShowWindow(SW_SHOW);     pDlg->IsContinue = TRUE; //<--ここでフラグを変更しているのに。   while(pDlg->IsContinue) {    MSG msg;    if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {      ::TranslateMessage(&msg);      ::DispatchMessage(&msg);    }   }   pDlg->DestroyWindow();   return 0; } ---- メインスレッドのSleep(0)で待つのを AfxGetApp()->PumpMessage()に変更すると ループを抜けるようなのですが、どうも納得できません。 上記のプログラムで問題、もしくはプロジェクトの 設定等に不備がある可能性がありましたら 御教授いただけたら幸いです。 よろしくおねがいいたします。

  • VC++2005のスレッド使用方法について

    現在、VC++2005 SP2にてDLLを作成しています。 DLLには一つスレッドがあり、開始関数が実行されれば、スレッドが起動。終了関数を実行すればスレッドを停止させたいと思っております。 関数を分けていますので、以下の内容をグローバルで宣言したいと考えています。 Thread^ oThread = gcnew Thread( gcnew ThreadStart( &CUart::ThreadProc ) );                                     ~~~~~~~~~~~~~~~~~~~~~~~~                                         実行関数です。 oThread->Start();  //開始関数のスレッド開始  oThread->Abort();  //終了関数のスレッド停止 現在、宣言をグローバルのところに配置して、ビルドすると エラー 1 error C3145: 'oThread' : グローバルまたは静的変数は、マネージ型 'System::Threading::Thread ^' を含むことはできません とエラーが発生してしまいます。 いろいろ調べましたが、なかなか進んでいない状態です。 使用方法が間違っているのでしょうか?申し訳ありませんが、教えてください。 もし、別の方法があればご教授願います。 よろしくお願いします。

  • MFCマルチスレッドについて

    MFCマルチスレッドについて COMやIOボードからの入力に応じて動作するアプリを作っています。 AfxBeginThreadにてそれぞれワーカスレッドを作成しCOMやIOから入力があれば AfxBeginThreadを呼んでいるクラスにあるメンバ関数を実行しようとしています。 AfxBeginThreadにて*thisを送り、制御関数内で、mycls->OnButton***()というような 感じで現在は作っています。(OnButton***になっているのはデバッグ用にボタンで あらかじめ作成している関数のためです。) このときに、mycls->OnButton***()は親スレッドで動いていると考えていいのですか? あくまで親スレッドのクラスのメンバ関数を制御関数が動いている子スレッドで実行 しているだけなのでしょうか? 実は、ログ表示のため制御関数の中(受信データを表示)と、mycls->OnButton***()の中 (作業結果を表示)に同じエディットコントロールへの表示部分があります。 表示部分の処理は、いったんCStringで読み込んできて最大文字数チェックを行い、 再度文字数を調節して書き直しということをやっているため、一応クリティカル セクションにはしているのですが、実際どう動いているか分からないため、やり忘れ ていることや、やってはいけないことをやってそうです。 すいませんがご教授願います。

  • ダイアログを終了させてもハンドルが1つ増加したまま。。。

    VC++のMFCを使ってダイアログベースのEXEを造っています。 ハンドルのリークが発生し、困っています。 <動作内容> メインのダイアログで、ボタン押下により別のダイアログを表示します。 DoModal()でモーダルダイアログを作成します。 別のプロセスからブロードキャストされるメッセージを処理したいため、 ボタン押下のルーチンで DoModal() せずに、スレッドを作成し、 そのスレッドで DoModal() を実行しています。 スレッド作成は AfxBeginThread() を使用しています。 <サンプルソース> ●メインダイアログ // ボタン押下のルーチン void CTestModalDlg::OnButton1() { AfxBeginThread( TestDlgThread, (LPVOID)this, THREAD_PRIORITY_NORMAL ); } // スレッド static UINT TestDlgThread(LPVOID pThis) { CTestDlg1 Dlg; Dlg.DoModal(); } ●DoModal() で表示されるダイアログ 何も手を加えてない、デフォルトのまま。 <結果> DoModal() で表示されたダイアログを CDialog::OnCancel() で終了させ、 メインのスレッドが終了しても、ハンドルカウントが1つ増加しています。 Sleep() を入れて値をみてみると、 ・スレッド作成:2増加 ・DoModal() でダイアログ表示:1増加 ・OnCancel() で終了:増減なし ・スレッド終了:2減少 =>結果、1増加となっていました。 以下のパターンでは問題ありませんでした。 ・スレッドを作成+終了(ダイアログ表示しない) ・スレッドを作成せずに、ボタン押下ルーチンから DoModal() でダイアログ表示+終了 ということで、AfxBeginThread()、DoModal() 自体は問題ないのですが、 スレッドを作成して DoModal() するとリークが発生します。 識者の方、原因、対策など、ご教授願います。

  • スレッド起動したフォームを正常に終了させる。

    Visual Studio 2005 C#.netです。 クラスからフォームをバックグラウンドスレッド起動して、そのフォームを起動したクラスから正常にフォームを消去させたい(終了)させたいのですが、どうすればいいのでしょうか? 現在、以下のプログラムにて実現していますが、Abortで強制終了させているのでDispose(); も行われていないと思います。 呼び出し側からアクションを起こしてAbortではなく、スレッド側から正常に終了させたいのです。 また、Showメソッドだとフォーム表示が一瞬で終わってしまうのは何故でしょうか? よろしくお願いいたします。 クラス: public class FormDisplayClass { //スレッド private System.Threading.Thread thread; //フォーム private TestForm TF = new TestForm();//フォームは別に存在するとします。 //表示メソッド public void Show() { //スレッド設定 this.thread = new System.Threading.Thread( new System.Threading.ThreadStart(FormShow)); //バックグラウンド this.thread.IsBackground = true; //スタート this.thread.Start(); } /// <summary> /// スレッドを終了させる。 /// </summary> public void Close() { this.thread.Abort(); } /// <summary> /// フォームを表示させる /// </summary> private void FormShow() { this.SWD.ShowDialog();//表示      (Showだと表示を持続できない) this.SWD.Dispose(); } #endregion } 呼び出し側: FormDisplayClass FDC = new FormDisplayClass();    private 表示メソッド { FDC.Show(); }    private 終了メソッド { sw.Close(); } } よろしくお願いします。