>スレッド動作を一旦中断(OnThreadCan)させてから中止(OnDestroy) させれば
>メモリリークは起きません。何か気付いた所がありましたらお願いします。
これ、たまたまスレッドが先に終わったんでしょう。
SetEventした直後にプログラムが終わったら、Threadが正常に終了する前に
プログラムが終了することになり、おかしいことになります。
もし各スレッドがちゃんとCPUリソースを割り振られていたなら、
SetEventした直後にWaitForSingleObject(m_pTermThreadsEvent~
して(Eventは立ってるからすぐに処理が戻ってきます)すぐに
終了することになります。ところが、ひとつ関数をかますことによって、
関数を読んだりモタモタしてるうちに、SetEventを察したスレッドの
方が終わる猶予ができるわけですよね。
多分、
>m_pTermThreadsEvent.SetEvent(); //停止信号をThreadProcに送る
Sleep(3000);
>WaitForSingleObject(m_pTermThreadsEvent, INFINITE); //スレッド終了待ち
とか入れれば、リークは起きないと思います。
スレッドはかなりシビアなタイミングで動きますから、しっかりと
内容を把握していないとバグの原因をめっけられません。
正しいのは、dairygoodsさんやTADさんのおっしゃるようにスレッドハンドルを
WaitForSingleObjectすることです。
1> void CThreadDlg::OnDestroy()
2> {
3> CDialog::OnDestroy();
4>
5> m_pTermThreadsEvent.SetEvent(); //停止信号をThreadProcに送る
6> WaitForSingleObject(m_pTermThreadsEvent, INFINITE); //スレッド終了待ち
7> }
5行目でm_pTermThreadEventはシグナル状態になります。
6行目でm_pTermThreadEventがシグナル状態になるまで待っていますが、
直前でシグナル状態にセットしているので、関数はすぐに戻ります。
CEventはデフォルトではオートイベントであり、一度シグナル状態で
あることを検出されると、非シグナル状態に自動的に戻ります。
そのため、ThreadProc() 関数内の、
> //停止信号チェック
> if(::WaitForSingleObject(m_pTermThreadsEvent, 0) == WAIT_OBJECT_0) {
の部分で、イベントがシグナル状態になっていることを検出するには、
この部分が偶然上記5行目と6行目の間で実行されたときだけです。
これは、滅多に起こりそうもありません。そのため、スレッドは終了しません。
偶然にもスレッド側でイベントがシグナル状態になったのを検出した場合は、
今度はメインスレッドの方が6行目で無限に待つことになります。
>CEventはデフォルトではオートイベントであり、一度シグナル状態で
>あることを検出されると、非シグナル状態に自動的に戻ります。
失礼しました。デフォルトはオートなんですね。
やはり、スレッドハンドル(ポインタ)で待機すべきですね。
あと、元発言のスレッドは時間がたてば終了するんですね。
(中断ってかいてあった (^^; )
TADさん、 dairygoodsさん、 Bunさん、 いもちぃさん 有難うございます。
こんなに難しい事をやっていたとは思ってもいませんでした(汗)。
>CWinThread* pThread = AfxBeginThread(...);
>...
>::WaitForSingleObject(*pThread, INFINITE);
この*pThreadを、使っているWaitForSingleObjectのすべてを入れ替えたところ、
OnThreadCanが効かなくなりました。
>今度はメインスレッドの方が6行目で無限に待つことになります。
同時に、OnDestroyのWaitForSingleObject(m_pTermThreadsEvent, INFINITE);
で永久に待ちつずけるようになりました。SetEventの引数はないので他の所も変更
しないと駄目なのかも知れませんね。
>WaitForSingleObject((HANDLE)m_pTermThreadsEvent, INFINITE);
この(HANDLE)m_pTermThreadsEventをやはり使っている所すべてを入れ替えたところ
OnDestroy(右上のX印)させてもメモリリークはなくなりました。ただ、終了コードが
0x2になりましたが、メモリリークとは別物かと考えています。
>これ、たまたまスレッドが先に終わったんでしょう。
ThreadProcの最高カウント値300を5000に変更し、カウント値を100,200,300,400で
中断し、すぐさま(マウスの移動時間)終了(OnDestroy)しても、メモリリークは
起きませんでした。皆さんの考えによると、この方式はおかしいと言う事なので
たまたま上手くいってるだけでしょうかね。
>こんなに難しい事をやっていたとは思ってもいませんでした(汗)。
わしもでーす。(大&&滝汗)
>この*pThreadを、使っているWaitForSingleObjectのすべてを入れ替えたところ、
>OnThreadCanが効かなくなりました。
そうなりますね。中断が必要ならEventオブジェクトは必要だと思います。
APIを使ったサンプルですが、下記のURLを参考にしてみてください。
(ぱっとしか見てないけど、結構感じはつかめるかも)
http://www.geocities.co.jp/SiliconValley-PaloAlto/5920/api_sample_sync12_c.html
> この*pThreadを、使っているWaitForSingleObjectのすべてを入れ替えたところ、
> OnThreadCanが効かなくなりました。
全て置き換えてはいけませんよ(^^;
メインスレッド(OnDestroy)が待つのは、「スレッドの終了」で、
ワーカースレッド(ThreadProc)が待つのは、「イベントがSetEventされたかどうか」です。
待つものが違うのですから、2つのWaitForSingleObjectが同じではうまくいきません。
最初のコードで、スレッド終了待ちの方だけ *pThread を待つように
変更すれば、正しく動作すると思います。
ところで、pThreadは、スレッドが終了すると自動的にdeleteされてしまいますので、
開始した直後に
pThread->m_bAutoDelete = FALSE;
としておいて、スレッドの終了を待った後、自分でdeleteする必要があります。
Bunさん、 dairygoodsさん 有難うございました。
TADさん、 いもちぃさん 有難うございました。
> http://www.geocities.co.jp/SiliconValley-PaloAlto/5920/api_sample_sync12_c.html
早速見て見ます。
>全て置き換えてはいけませんよ
すぐやってみます。
皆さんから、いろいろアドバイスを頂き有難うございました。
ラウンジを大変消費してしまいましたので、これでとりあえず「解決」に
したいと思います。
>全て置き換えてはいけませんよ
>すぐやってみます。
「解決」後ですが、上記、リークなしで動作しましたので追記します。