WaitForSingleObjectでタイムアウトしてしまう – プログラミング – Home

通知
すべてクリア

[解決済] WaitForSingleObjectでタイムアウトしてしまう


kai
 kai
(@kai)
ゲスト
結合: 23年前
投稿: 64
Topic starter  

お世話になっています。

環境 : Win2000, VC6.0, MFC使用, MDIです。

ワーカスレッドを起動し、プログラムの終了時にイベントをシグナルにすると
WaitForSingleObject の戻り値が WAIT_TIMEOUT になってしまいます。
ワーカスレッド内のSendMessage()はViewに対してユーザー定義メッセージを
送信しています。このSendMessage()をコメントにすると、WaitForSingleObjectは
WAIT_OBJECT_0 を返します。(期待する動作)
SendMessage()に時間がかかるのかと思い、計測してみたら 10 ミリ秒程度なので
問題はなさそうです。
なぜタイムアウトになってしまうのか、原因がわかりません。

識者の方々、アドバイスをお願いします。m(__)m

/////////////////////////////////////////////
// スレッドの起動

m_pThread = AfxBeginThread(Choge::WorkerThread, &m_ThInfo);

/////////////////////////////////////////////
// プログラム終了時の処理

::SetEvent(m_ThInfo.hEvent);
DWORD dwResult = ::WaitForSingleObject(m_pThread->m_hThread, 5000);
●ここでタイムアウトしてしまう

/////////////////////////////////////////////
// Choge::WorkerThread()

// ここで pTh->hEvent は 上記の m_ThInfo.hEvent です
while (::WaitForSingleObject(pTh->hEvent, 0) == WAIT_TIMEOUT) {

bRet = ::ReadFile(hF, (LPVOID)RcvBuf, byte, &dwReadByte, NULL);
if (bRet) {
if ((RcvBuf[0] == m_cFirstRcvChar) && (dwReadByte == byte)) {

DWORD dwTime1 = GetTickCount();

::SendMessage(pTh->hWnd, WM_RCVDATA, (WPARAM)RcvBuf, (LPARAM)
dwReadByte);

DWORD dwTime2 = GetTickCount();

DWORD dwTime3 = dwTime2 - dwTime1; // dwTime3 = 10msec

}
}
}


引用未解決
トピックタグ
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

WaitForSingleObjectを呼び出した側はロックされていますので、
メッセージを投げられても受け取れません。
よってSendMessage呼び出しは終了することがなく、タイムアウトになります。


返信引用
kai
 kai
(@kai)
ゲスト
結合: 23年前
投稿: 64
Topic starter  

dairygoodsさん レスありがとうございます。

>WaitForSingleObjectを呼び出した側はロックされていますので、
>メッセージを投げられても受け取れません。

すみません、意味がわからないので、もう少し詳しく教えて
いただけませんでしょうか?

また、解決策はありますでしょうか?
よろしくお願いします。m(__)m


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

終了処理関数の外側でMFCが何をやっているかというと、
こんなイメージです。

while(..) {
..
SendMessage等で届いたメッセージを処理する(A)
...
if (プログラム終了時のイベント) {
OnEnd();
}
}

void OnEnd() {
::SetEvent(m_ThInfo.hEvent);
DWORD dwResult = ::WaitForSingleObject(m_pThread->m_hThread, 5000);
}

WaitForSingleObjectを呼び出すと、スレッドが終了するか
タイムアウトするまで関数から戻らないので、(A)の部分が実行されません。

ワーカースレッドの方はSendMessageでメッセージを送って
受け取ってくれるのをず~っと待っていますが、
(A)が実行されないのでSendMessage関数は永遠に終了しません。

> また、解決策はありますでしょうか?

タイマーを使ってスレッドの終了を監視すればよいでしょう。
OnTimer(..) {
..
if(::WaitForSingleObject(m_pThread->m_hThread, 0)==WAIT_OBJECT_0)
終了
}


返信引用
kai
 kai
(@kai)
ゲスト
結合: 23年前
投稿: 64
Topic starter  

dairygoodsさん 早速のレスありがとうございます。

>終了処理関数の外側でMFCが何をやっているかというと、
>こんなイメージです。

よくわかりました。
ご丁寧にありがとうございます。

>> また、解決策はありますでしょうか?
>タイマーを使ってスレッドの終了を監視すればよいでしょう。

こちらもよくわからないのですが
プログラム終了時のイベントで
::SetEvent(m_ThInfo.hEvent);だけおこない、タイマーで

if(::WaitForSingleObject(m_pThread->m_hThread, 0)==WAIT_OBJECT_0)
終了

するということでしょうか?
そうだとすると、この場合終了しないということはないでしょうか?
また、このifを判定するときにすでにスレッドが終了していても
WAIT_OBJECT_0が返ってくるのでしょうか?

よろしくお願いします。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

> また、このifを判定するときにすでにスレッドが終了していても
> WAIT_OBJECT_0が返ってくるのでしょうか?

スレッドが終了していてもWAIT_OBJECT_0を戻します。

ところで、m_pThreadはスレッドが終了すると勝手にdelete
されてしまいますので、スレッドを起動したときに

m_pThraed->m_bAutoDelete = FALSE;

としておいて、

> if(::WaitForSingleObject(m_pThread->m_hThread, 0)==WAIT_OBJECT_0)
{
delete m_pThread;
終了
}

と自分で削除する必要があります。


返信引用
kai
 kai
(@kai)
ゲスト
結合: 23年前
投稿: 64
Topic starter  

>スレッドが終了していてもWAIT_OBJECT_0を戻します。
>ところで、m_pThreadはスレッドが終了すると勝手にdelete
>(省略)
>と自分で削除する必要があります。

なるほどです。
よくわかりました。ありがとうございます。

ただ、タイマーを使った方法ではうまくいきません。
というのは、CMainFrame::OnClose()でSetEvent()するので
その後にそのまま、CMDIFrameWnd::OnClose()が呼ばれて
終了せざるを得ないからです。

>OnTimer(..) {
> ..
> if(::WaitForSingleObject(m_pThread->m_hThread, 0)==WAIT_OBJECT_0)
> 終了
>}

判定する前にすでに終了処理がおこなわれてしまいます。

タイマーを使うのが一般的な方法なのでしょうか?

SetEventを使うのをやめて、volatile修飾したフラグで制御したら
うまくいったようなのですが。。。こちらでも大丈夫でしょうか?
よろしくお願いします。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

終了関数内でメッセージ処理してしまうという方法もあります。

void OnClose()
{
SetEvent(m_ThInfo.hEvent);
while (WaitForSingleObject(m_pThread->m_hThread, 0)==WAIT_TIMEOUT) {
MSG msg;
if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) {
AfxGetApp()->PumpMessage();
}
}
}

> SetEventを使うのをやめて、volatile修飾したフラグで制御したら
> うまくいったようなのですが。。。こちらでも大丈夫でしょうか?
どちらでも同じような気がします。
たまたまSendMessageからイベントチェックの間に
イベントがセットされれば、ちゃんと終了します。


返信引用
kai
 kai
(@kai)
ゲスト
結合: 23年前
投稿: 64
Topic starter  

>どちらでも同じような気がします。
>たまたまSendMessageからイベントチェックの間に
>イベントがセットされれば、ちゃんと終了します。

ありがとうございました。m(__)m
安心しました、解決です。(^_^;


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました