如何正確的關閉 MFC 線程

前言: 多線程

  近日在網上看到不少人問及如何關閉一下線程,可是我看網上給出的並不詳細,並且有些方法仍是錯誤的。小弟在此拙做一篇,不談別的,只談及如何正確的關閉MFC的線程,至於Win32和C RunTime的線程暫不涉及。 函數

一.關於MFC的線程 oop

  1.MFC的線程有兩種,一種稱爲Work線程,一種稱爲UI線程。通常狀況下Work線程與UI線程的區別主要在於UI線程有消息隊列(並非有沒有界面,這點要注意,UI線程也是能夠沒有界面的)。 ui

  2.建立這兩種線程的區別也不大,能夠從建立函數看出。 spa

[cpp]  view plain copy
  1. // Work線程  
  2. CWinThread* AfxBeginThread(  
  3.       AFX_THREADPROC pfnThreadProc,  
  4.       LPVOID pParam,  
  5.       int nPriority = THREAD_PRIORITY_NORMAL,  
  6.       UINT nStackSize = 0,  
  7.       DWORD dwCreateFlags = 0,  
  8.       LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL  
  9.      );  
  10.   
  11. // UI線程  
  12. CWinThread* AfxBeginThread(  
  13.       CRuntimeClass* pThreadClass,  
  14.       int nPriority = THREAD_PRIORITY_NORMAL,  
  15.       UINT nStackSize = 0,  
  16.       DWORD dwCreateFlags = 0,  
  17.       LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL  
  18.      );  

關於函數的具體使用,請查閱MSDN,這裏不涉及。 .net

二. 結束線程前的注意事項 線程

  在結束一個線程前,只有一點要注意,那就是m_bAutoDelete 的狀態。(什麼?不知道m_bAutoDelete ?!!快去查閱MSDN吧)。 設計

[c-sharp]  view plain copy
  1. m_bAutoDelete = FALSE; // 表示你本身管理 CWind 對象,包括它的清理  
  2.   
  3. m_bAutoDelete = TRUE;  // 默認值, 系統會本身清理 CWind 對象  

m_bAutoDelete = TRUE; 系統本身清理CWind對象,固然還包括CloseHandle(),ExitInstance()等等一堆函數的調用。 對象

m_bAutoDelete = FALSE; 那麼就必定要記得本身在用完後調用delete刪除建立線程的對象,這一點極爲重要,由於不調用delete必定會有內存泄漏問題 blog

總之m_bAutoDelete 的值對結束工做是很重要的,這點必定要注意。

三.正確的結束一個Work線程

  由於Work線程是一個全局函數,或者是一個Static函數,因此它的運行完成也就是它的正常退出了。(什麼?不明白,示例代碼以下)

  1.狀況一:

[c-sharp]  view plain copy
  1. UINT WorkFunc(LPVOID pParam)  
  2. {  
  3.   // 工做  
  4.   ......  
  5.    return 0;  // 就算正常退出了,簡單吧  
  6. }  

  2.狀況二:

Work線程是個死循環或一時半會兒出不來,這時要主線程要發個消息給Work線程,讓他退出。

[cpp]  view plain copy
  1. UINT WorkFunc(LPVOID pParam)  
  2. {  
  3.   for(;;)  
  4.   {  
  5.    // ...  
  6.   if( WAIT_OBJECT_0 == WaitForSingleObject(m_hThread, INFINITE)} // 收到激發態的消息  
  7.     {  
  8.       return 0;//正常退出  
  9.      }  
  10.   
  11.  }//end for  
  12.     
  13.  return 0;  
  14. }  

關於主線程發一個激發態的消息給Work線程,有多種方法,如在主線程裏調用SetEvent()等等,你想用什麼都行,可是最好不要在Work線程裏用Busy loop的方法。至於爲何,請參閱《Win32多線程程序設計》上面的論述。

四.正確結束一個UI線程

  由於UI線程有消息隊列,因此結束一個UI線程最好的方法是發一個WM_QUIT消息給消息隊列,方法不少如:PostQuitMessage(),PostThreadMessage()等等。可是發出消息後最好等待看UI線程是否已經退出(不少人都沒有說起這一點,可是實際工做中發現,加上這一點是多麼的重要)

[c-sharp]  view plain copy
  1. // 主線程結束UI線程的代碼  
  2. if(pThread)   
  3. {  
  4.   // 1. 發一個WM_QUIT 消息結 UI 線程  
  5.   pThread->PostThreadMessage(WM_QUIT, NULL, NULL);  
  6.                   
  7.  // 2. 等待 UI 線程正常退出  
  8.  if (WAIT_OBJECT_0 == WaitForSingleObject(pThread->m_hThread, INFINITE))  
  9.  {  
  10.     // 3. 刪除 UI 線程對象,只有當你設置了m_bAutoDelete = FALSE; 時才調用  
  11.   delete   pThread;   
  12.  }  
  13.   
  14. }  

五.關於幾個問題的解答

1.問:爲何個人UI線程沒有調用ExitInstance()?

  答:最大的多是你的WM_QUIT消息沒有通知到UI線程。爲了保險期間最好調用PostThreadMessage(),這樣能夠指定線程的ID。固然若是你對消息比較熟悉的話,也能夠拋一個消息到最頂層。

2.問:爲何個人UI線程沒有調用析構函數?

  答:檢查看你的m_bAutoDelete = FALSE,若是是的話,那麼看你的線程對象是否已經delete了。通常狀況下調用delete會調用析構函數

3.問:在UI線程中沒有調用WaitForSingleObject(),會怎麼樣?

  答:咱們知道在PostMessage()以後,函數會立刻返回,如查沒有wait...(),那麼緊接着就調用了delete,頗有可能對象作的退出操做過程尚未完成時,又把對象delete掉了,結果仍是沒有正常結束。(注:WM_QUIT消息以後會觸發一堆函數,這個時間是不定的,因此最好Wait...纔是正道。)

六.最後不肯提的函數

  幾乎每本講線程的書都會提到下面的函數:

  void AfxEndThread(UINT nExitCode);

  TerminateThread();

  ......還有其它的一些極端的函數

個人觀點是:最好不要使用,除非你知道要發生什麼!!

相關文章
相關標籤/搜索