您的位置:首页 > 产品设计 > UI/UE

MFC工作线和UI主线程互锁问题的解决方法

2012-03-01 12:19 190 查看
在以下代码中,线程Thread退出时,可能会要UI线程互锁

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


原链接地址——

http://blog.sina.com.cn/s/blog_5ee42ba30100cbjm.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: