スレッドで稀にタイムアウトになってしまう

[戻る]
いっし 2008/07/23(水) 14:44:51
VC++6なんですが
IMPLEMENT_DYNCREATE(AAA_Thread, CWinThread)

BOOL AAA_Thread::InitInstance()
{
いろんな処理
return FALSE; ←でスレッドを終了
}

int AAA_Thread::ExitInstance()
{
終了処理
iRet = CWinThread::ExitInstance();
return iRet;
}

こんな感じのスレッドクラスが2つあります。(もうひとつはBBB_Threadとします)

メインの処理でAfxBeginThreadをしてm_bAutoDelete = FALSE;をして
ResumeThread();で開始します。

とあるタイミングでAAA_ThreadとBBB_Threadのスレッドを何回か開始しては
WaitForSingleObjectで待って終わったらまた開始という感じで処理をするのですが
ごく稀にWaitForSingleObjectでタイムアウトになってしまいます。
タイムアウト時間はかなり余裕があります。
ログを見るとスレッドクラスのInitInstanceの最後の処理までは
終わっているみたいなのですがなぜかWaitForSingleObjectでタイムアウトか
返ってきます。
作り的には問題ないでしょうか?
何か原因があるのでしょうか?
以上よろしくお願いします。

ITO 2008/07/23(水) 20:05:18
> メインの処理でAfxBeginThreadをしてm_bAutoDelete = FALSE;をして
> ResumeThread();で開始します。
ワーカスレッドじゃないと思うのですが、通常起動ではだめなんですか?

> BOOL AAA_Thread::InitInstance()
> {
>  いろんな処理
>  return FALSE; ←でスレッドを終了
> }
普通こういう処理はしません。
>return FALSE;
は初期化に失敗したときだけです。
WaitForSingleObjectで待っているのとInitInstance()で処理するとき
が合ってないとか。
InitInstance()を抜けた後、WaitForSingleObjectで待っていすと
いうことはないですか?

いっし 2008/07/24(木) 14:49:37
MFCでユーザーインターフェイススレッドとして作ってありますので
AfxBeginThreadで問題ないと思います。(MFC以外ならCreateThreadなどかな・・?)

>普通こういう処理はしません。
>return FALSE;
>は初期化に失敗したときだけです。

そんな気はしていたんですが・・初期化に失敗したら
WaitForSingleObjectでタイムアウトという訳でも・・

>InitInstance()を抜けた後、WaitForSingleObjectで待っていすと
>いうことはないですか?

動き的にはもうスレッドがInitInstance()を抜けて終わってから
WaitForSingleObjectで待つという形になっています。
スレッドがInitInstance()を抜けて終わっているので
通常はWaitForSingleObjectでタイムアウトではなく
WAIT_OBJECT_0が返ってきています。

rin 2008/07/24(木) 15:29:49
スレッド作成・起動部分、WaitForSingleObjectによる待機部分のソースを
提示してみてはどうでしょうか?

いっし 2008/07/24(木) 18:17:36
//スレッドを生成〜開始
CAAA_Thread    *A_pThread;
A_pThread = (CAAA_Thread*)AfxBeginThread(
  RUNTIME_CLASS(CAAA_Thread),
  THREAD_PRIORITY_NORMAL,
  0,
  CREATE_SUSPENDED);
A_pThread->m_bAutoDelete = FALSE;
A_pThread->ResumeThread();

//スレッド終了待ち
dwRet = ::WaitForSingleObject(A_pThread->m_hThread, (100 * 1000));
if(dwRet == WAIT_TIMEOUT) {
  ログからここに入っていた
}

ログからInitInstanceは最後まではスレッド終了待ちの前に行っているので
ExitInstanceでフリーズしているのかもしれません。
処理的に止まりそうなところは無いと思うのですが・・
(超極稀にしか発生しないってのが難しいところです)

int CAAA_Thread::ExitInstance()
{
int        iRet;
try{
 if(this->COMオブジェト != NULL) {
    this->COMオブジェト.Release();
    this->COMオブジェト = NULL;
 }
} catch(...) {
//無視
}
CoUninitialize(); (InitInstanceの中でCoInitialize(NULL)やCOMオブジェクト生成)

iRet = CWinThread::ExitInstance();
return iRet;
}

たぶんスレッド自体には問題なさそうなんでどっかで何か壊しちゃっているのかも
しれませんね・・・

ITO 2008/07/25(金) 13:27:31
> A_pThread->m_bAutoDelete = FALSE;
CAAA_Threadのオブジェクトが終了しないとだめだとおもいますが?
ユーザーインターフェイススレッドの時は設定しないほうがいいと思います。

> dwRet = ::WaitForSingleObject(A_pThread->m_hThread, (100 * 1000));
このやりかたはワ−カスレッドの時だと思います。
ExitInstance()時にSetEventで処理したうハンドルを
使ったほうがいいとおもいます。

いっし 2008/07/25(金) 14:35:08
>CAAA_Threadのオブジェクトが終了しないとだめだとおもいますが?
>ユーザーインターフェイススレッドの時は設定しないほうがいいと思います。
自動廃棄するとA_pThread->m_hThreadが参照できなくなるので
まずいのではないでしょうか?

AfxBeginThreadの場合はWaitForSingleObjectではなく
GetExitCodeThreadでないと失敗する場合があるということを聞きました。
調べましたが事例が見つかりませんでしたが
心当たりあるかたはおりませんでしょうか?
とりあえずGetExitCodeThreadによる終了判定にしようと思います。

いっし 2008/07/25(金) 14:48:13
気づくのが遅れましたが
ExitInstance()でSetEventでやる場合には
自動廃棄でよさそうですね。

ITO 2008/07/25(金) 20:57:03
> A_pThread->m_bAutoDelete = FALSE;
こうすると、オブジェクトだけが破棄されずに残るみたいですね。
ワーカスレッドとは違うみたいです。

> AfxBeginThreadの場合はWaitForSingleObjectではなく
> GetExitCodeThreadでないと失敗する場合があるということを聞きました。
AfxBeginThreadの戻り値は「CWinThread」のポインターです。
ですから、戻り値を記憶して、「CWinThread」のポインターのハンドルを
利用しないといけないと思います。
MFCのスレッドの終了方法の説明でGetExitCodeThreadの使い方が書いてあります。

>とりあえずGetExitCodeThreadによる終了判定にしようと思います。

> ExitInstance()でSetEventでやる場合には
> 自動廃棄でよさそうですね。
これが、ユーザーインターフェイススレッドの場合の方法だと思います。

1. SetEventのハンドルをWaitForSingleObjectで待つ。
2. GetExitCodeThreadで終了判定する。
の手順でいいと思います。
2.は駄目押しです。
何か複雑な処理をしていれば別ですが、
Sleepで一定時間待てばいいと思います。

いっし 2008/07/28(月) 13:25:23
[[解決]]
いろいろありがとうございました。

古いスレッドには追加発言できません。