在以下代码中,线程Thread退出时,可能会要UI线程互锁
究其原因,是因为WaitForSingleObject函数会使线程的释放CPU时间,类似于Sleep的行为,如果此时 Work线程执行到操作UI元素的代码,但此时UI线程事实上已经处于休眠状态,因此操作UI元素的代码要等到UI线程被唤醒才会返回,这样一来,UI线程和Work线程便陷于互相等待的境地,死锁便由此发生。
解决方法:
void CTagScanPCDlg::StopRead()
{
if (m_hEvent != NULL) //线程结束等待事件
{
SetEvent(m_hEvent);
}
if (m_hThreadRead != NULL)
{
WaitForSingleObject(m_hThreadRead,INFINITE); //等待线程结束
DWORD dwExitCode = 0;
m_hThreadRead = NULL;
}
m_hEvent = NULL;
}
DWORD WINAPI CTagScanPCDlg::ReadThread(LPVOID lpParam)
{
//……
while (WaitForSingleObject(pDlg->m_hEvent,0) == WAIT_TIMEOUT)
{
//……
pDlg->SetDlgItemText(IDC_TAGGROUP,(LPCTSTR)szTextTitle); //操作UI元素
//……
}
//……
}
究其原因,是因为WaitForSingleObject函数会使线程的释放CPU时间,类似于Sleep的行为,如果此时 Work线程执行到操作UI元素的代码,但此时UI线程事实上已经处于休眠状态,因此操作UI元素的代码要等到UI线程被唤醒才会返回,这样一来,UI线程和Work线程便陷于互相等待的境地,死锁便由此发生。
解决方法:
既然死锁的原因是由于UI线程和Work线程的互相等待,那我们就尽量避免这种情况的发生。在StopRead函数中作如此修改:
if (m_hEvent != NULL) //线程结束等待事件
{
SetEvent(m_hEvent);
Delay(10000,m_hDelayEvent)
//Delay为一延时函数,m_hDelayEvent为由CreateEvent创建的事件,创建于Work线程创建之前,当m_hDelayEvent被重置时,Delay函数便会返回
}
在ReadThread函数返回前,加如下代码:
SetEvent(pDlg->m_hDelayEvent); //重置m_hDelayEvent
如此改动之后,由UI线程不会陷入长时间休眠,因此Work线程访问UI的代码也不会陷入等待状态,死锁便不会发生。
Delay函数如下:
void Delay(DWORD dwTime,HANDLE hEvent)
{
DWORD dwStart = GetTickCount();
if (hEvent != NULL)
{
while(WaitForSingleObject(hEvent,0) == WAIT_TIMEOUT)
{
MSG msg;
//响应其它消息的处理
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if(GetTickCount() - dwStart > dwTime)
return;
::Sleep(1);
}
}
else
while(1)
{
MSG msg;
//响应其它消息的处理
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if(GetTickCount() - dwStart > dwTime)
return;
::Sleep(1);
}
}
原链接地址——