先请大家看如下MFC代码
//创建线程代码
void CTestWinThreadDlg::OnButtonStart() 
{
CWaitCursor wait;
//m_hTestThreadKillEvent为HANDLE变量
m_hTestThreadKillEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
//m_pTestThread为CWinThread指针,TestThread为线程函数
m_pTestThread = AfxBeginThread(TestThread,this,THREAD_PRIORITY_ABOVE_NORMAL,0,CREATE_SUSPENDED);
m_pTestThread->m_bAutoDelete = false;
m_pTestThread->ResumeThread();
}//结束线程代码
void CTestWinThreadDlg::OnButtonStop() 
{
CWaitCursor wait;
SetEvent(m_hTestThreadKillEvent);
//EventDelay(m_pTestThread->m_hThread,INFINITE);
//结束时会在这里发生死锁,因为WaitForSingleObject会使主线程进入休眠状态
//而TestThread线程这里又要仿问界面,要等待主线程回应消息,因此陷入互相等待
//的死锁状态
WaitForSingleObject(m_pTestThread->m_hThread,INFINITE);
delete m_pTestThread;
m_pTestThread = NULL;
CloseHandle(m_hTestThreadKillEvent);
m_hTestThreadKillEvent = NULL;
}//仿问对话框界面的线程
UINT CTestWinThreadDlg::TestThread(void *p)
{
CTestWinThreadDlg *pDlg = (CTestWinThreadDlg *)p;
int nCount = 1;
while(WaitForSingleObject(pDlg->m_hTestThreadKillEvent,0) == WAIT_TIMEOUT)
{
for (int i = 0;i < 2000;i ++)
{
nCount ++;
//这里只是一个演示,代表访问界面控件的一个操作,实际的项目中可能是其它操作
::SetDlgItemInt(pDlg->m_hWnd,IDC_EDIT_COUNT,nCount);
}
TraceMsg(_T("In TestThread \r\n"));
Sleep(10);
} TraceMsg(_T("TestThread  Will Return!\r\n"));
return 0L;
}
线程启动后,可以看到界面上的计数在增大.
但在结束线程时,在执行WaitForSingleObject(m_pTestThread->m_hThread,INFINITE)时,就可能发生死锁,如果不等线程结束又不知道线程究竟是何时结束的(对于一个执行耗时操作的线程);
上面的代码中有一个被屏蔽的函数,EventDelay(),其代码如下://条件延时函数,当hEvent重置或等待时间超过dwTime ms时,函数返回
void EventDelay(HANDLE hEvent,DWORD dwTime)
{
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);
}
}
}
当要结束线程时,若以EventDelay(m_pTestThread->m_hThread,INFINITE)取代WaitForSingleObject(m_pTestThread->m_hThread,INFINITE)时,主界面不会陷入死锁,也可以正常等到线程结束,但是鼠标的沙漏光标会变回指针状态,这时用户可以同时进行其它操作,可能会点关闭窗口等,而这些在关闭线程时可能是不允许操作的.这里我的问题是,如何能够安全等待线程结束,又能防止用户执行其它不安全操作.

解决方案 »

  1.   

    先屏蔽这句看看,::SetDlgItemInt(pDlg->m_hWnd,IDC_EDIT_COUNT,nCount);,这里要等主界面,可能会产生死锁,想想用其他办法。
      

  2.   

    PostMessage/SendMessage发送消息到界面线程上,让界面线程去更新控件信息
      

  3.   


    用SendMessage也会导致死锁的,因为SendMessage是同步的,必须等主线程响应消息之后,SendMessage才会返回,主线程一旦调用Wait...函数,SendMessage立即陷入死锁,这是SetDlgItemInt结果是一样的.PostMessage是虽然是异步的,但是如果通过PostMessage传送数据是可能被丢失的.