天天看點

VC++關于使用WaitForSingleObject等待線程安全退出,出現當機問題的解決

1、MFC項目場景如下:

主線程建立了子線程:

CWinThread *m_pThread_SysReset;

m_pThread_SysReset= AfxBeginThread(ThreadSysReset this);

主界面等待子線程退出時,主線程主動調用了函數:

WaitForSingleObject(m_pThread_SysReset->m_hThread, INFINITE);

目的是讓子待線程安全退出,但是子線程此時正在執行SendMesage發消息函數,主線程就會卡死。而如果子線程改為PostMessage發就不會卡死。為什麼呢?

原來在工作線程中使用了SendMesage,它是阻塞方式發消息,這樣的話在主線程中使用了waitforSingleObject,主線程就會被阻塞,要是工作線程也使用了消息循環與主線程相關的操作,那麼因為主線程已經被阻塞了,是以子線程得不到相應,那麼就出現假死了。

實際上,我們可以不使用WaitForSingleObject,因為MFC主線程在不被關閉的話是不會結束的,是以不能使用WaitForSingleObject這樣的函數進行等待。但是很多情況下,我們又需要知道我們建立的工作線程的情況,是以還是需要了解工作線程的傳回值。那麼我們可以使用微軟提供的另一個函數MsgWaitForMultipleObjects。

2、怎麼解決SendMessage當機問題?使用以下源碼即可解決!不再使用WaitForSingleObject,而是使用MsgWaitForMultipleObjects函數。

如此一來,無論子線程怎麼發消息,SendMessage也好,PostMessage也罷,都OK!

m_pThread_SysReset = ThreadFun_StartRun(&m_pThread_SysReset, ThreadSystemReset, this);
void CViewImage::ThreadFun_ExitThread(void)
{
    m_bExit = true;
    ThreadFun_WaitForObject(&m_pThread_SysReset);//等待線程退出
}
CWinThread *CViewImage::ThreadFun_StartRun(CWinThread **pThread, AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority)
{
    if (*pThread != NULL)
    {
  delete *pThread;
  *pThread = NULL;
    }
    //啟動線程,初始為挂起狀态
    *pThread = AfxBeginThread(pfnThreadProc, pParam, nPriority, 0, CREATE_SUSPENDED);
    if (*pThread != NULL)
    {
  //線程結束時不自動撤銷
  (*pThread)->m_bAutoDelete = FALSE;
  //恢複線程運作
  (*pThread)->ResumeThread();
    }
    return *pThread;
}
void CViewImage::ThreadFun_WaitForObject(CWinThread **pThread)
{
    if (*pThread == NULL)
    {
  return;
    }
    while (1)
    {
  DWORD result;
  MSG msg;
  result = MsgWaitForMultipleObjects(1, &(*pThread)->m_hThread, FALSE, INFINITE, QS_ALLINPUT);
  if (result == WAIT_OBJECT_0 + 1)
  {
    //響應windows消息
    PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  else
  {
    //線程運作結束(result==WAIT_OBJECT_0) ||
    //傳遞了一個無效的句柄(result==WAIT_FAILED) ||
    //線程等待時間已到(result==WAIT_TIMEOUT) ||
    //其他情況(...)
    break;
  }
    }
    delete *pThread;
    *pThread = NULL;
}      

繼續閱讀