在程序退出时,我们通常都会使用 WaitForSingleObject 等函数等待指定的信号或等待线程析构。最近在开发程序时突然遇到了在析构函数中使用 WaitForSingleObject 等待线程结束时造成程序阻塞的情况。经过仔细分析发现是在线程执行过程中更新了界面资源,而(UI线程)主线程此时被 WaitForSingleObject 阻塞(消息循环机制被阻塞),导致界面资源得不到更新,造成死锁。

经过查找相关资料,发现可以使用 MsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx 替代WaitForSingleObjectMsgWaitForMultipleObjects 等函数。

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)
}

标签: 死锁, WaitForSingleObject, 程序退出, 阻塞

添加新评论