程序退出时使用WaitForSingleObject导致程序阻塞的原因及解决方法
在程序退出时,我们通常都会使用 WaitForSingleObject
等函数等待指定的信号或等待线程析构。最近在开发程序时突然遇到了在析构函数中使用 WaitForSingleObject
等待线程结束时造成程序阻塞的情况。经过仔细分析发现是在线程执行过程中更新了界面资源,而(UI线程)主线程此时被 WaitForSingleObject
阻塞(消息循环机制被阻塞),导致界面资源得不到更新,造成死锁。
经过查找相关资料,发现可以使用 MsgWaitForMultipleObjects
或 MsgWaitForMultipleObjectsEx
替代WaitForSingleObject
、MsgWaitForMultipleObjects
等函数。
MsgWaitForMultipleObjects
可以等待直到指定的一个或全部对象都在信号状态或超时间已到。这些对象可包括输入事件对象,可以用 dwWakeMask
参数指定。当有界面资源更新时使用 PeekMessage
处理消息,解决死锁问题。
代码如下:
DWORD dwWait;
do
{
dwWait = MsgWaitForMultipleObjects(1, &m_dirWatch.m_pCalcThread->m_hThread, FALSE, 5000, QS_ALLINPUT); // wait five seconds
switch (dwWait)
{
case WAIT_OBJECT_0:
// handle became signalled!
break;
case WAIT_OBJECT_0 + 1:
{
// This thread awoke due to sent/posted message
// process the message Q
//
// There is a message in this thread's queue, so
// MsgWaitForMultipleObjects returned.
// Process those messages, and wait again.
MSG msg;
while(PeekMessage(&msg, NULL, 0,0, PM_REMOVE))
{
if( msg.message != WM_QUIT)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
/****
This appears to be causing quite a lot of pain, to quote Mustafa.
// it's the WM_QUIT message, put it back in the Q and
// exit this function
PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam );
bWMQuitReceived = true;
****/
break;
}
}
}
break;
case WAIT_TIMEOUT:
{
TRACE(_T("WARNING: Possible Deadlock detected! ThreadID: %d File: %s Line: %d\n"), GetCurrentThreadId(), _T(__FILE__), __LINE__);
}
break;
}//end switch(dwWait)
}