程序退出时使用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) }