windows中結束線程的方式

來源:互聯網
上載者:User

windows作業系統中,建立的線程有以下4種終止方式

1. 線程函數返回

當線程函數返回時,該線程會被終止,始終應該採用該方式來結束線程的運行,因為這是確保所有線程資源被正確清除的唯一辦法。如果線程按照該方式成功返回,則:

1)線程函數中建立的所有C++對象均能通過他們的解構函式正確的被撤銷

2)作業系統將正確的釋放線程運行棧所使用的記憶體

3)系統將線程的結束代碼(線上程的核心對象中維護)設定為線程函數的傳回值

4)系統將該線程核心對象的使用計數遞減

2.ExitThread函數

可以調用該函數,強制終止線程的運行。該函數將導致作業系統清除該線程所使用的所有作業系統資源。但是,C++資源(如類對象)將不被撤銷。該方法通常是windows用來撤銷線程的函數。因此,最好採用方法1來退出線程,而不是通過調用該函數來返回。

3.TerminateThread函數

調用該函數也能終止線程的運行,但與ExitThread函數不同,後者總是撤銷調用的線程,而前者能夠撤銷任何線程。TerminateThread是非同步啟動並執行函數,也就是說,它告訴系統你想要線程終止運行,但是,該函數返回時,不能保證線程被撤銷。如果需要確切地知道該線程已經終止運行,必須調用WaitForSingleObject或類似函數。當使用方法1和方法2撤銷線程時,該線程的記憶體棧空間也被撤銷。而如果使用TerminateThread,那麼在擁有該線程的進程終止運行之前,系統不撤銷該線程的運行棧。

4.進程終止運行時終止線程

在進程終止運行時,該進程中的所有線程全部終止運行,由於整個進程已經被關閉,進程所使用的所有資源肯定已被清除。這當然包括所有線程的棧空間。使用ExitProcess和TerminateProcess函數,會導致進程中的剩餘線程被強制撤銷,就像從每個剩餘的線程調用TerminataProcess一樣,因此,這也意味著正確的應用程式清除沒有發生,即C++對象解構函式沒被調用,資料沒有轉移至磁碟等等。

總結以上4種方法,通常,我們應當始終採用第一種方法來終止線程的運行。

我們可以在主線程將要退出時,給子線程發訊息,或者別的方式,告訴子線程,讓子線程自動結束。

 

 

 

今天看了點關於Windows多線程的東西,摘抄點關於CloseHandle的內容放於此,以便以後參考。

主要是《Windows核心編程》裡的兩小節:

3.1.1 核心對象的使用計數
            核心對象由核心所擁有,而不是由進程所擁有。換句話說,如果你的進程調用了一個建立核心對象的函數,然後你的進程終止運行,那麼核心對象不一定被撤消。在大多數情況下,對象將被撤消,但是如果另一個進程正在使用你的進程建立的核心對象,那麼該核心知道,在另一個進程停止使用該對象前不要撤消該對象,必須記住的是,核心對象的存在時間可以比建立該對象的進程長。
            核心知道有多少進程正在使用某個核心對象,因為每個對象包含一個使用計數。使用計數是所有核心物件類型常用的資料成員之一。當一個對象剛剛建立時,它的使用計數被置為1。然後,當另一個進程訪問一個現有的核心對象時,使用計數就遞增1。當進程終止運行時,核心就自動確定該進程仍然開啟的所有核心對象的使用計數。如果核心對象的使用計數降為0,核心就撤消該對象。這樣可以確保在沒有進程引用該對象時系統中不保留任何核心對象。
3.2.2 關閉核心對象
            無論怎樣建立核心對象,都要向系統指明將通過調用C l o s e H a n d l e來結束對該對象的操作:該函數首先檢查調用進程的控制代碼表,以確保傳遞給它的索引(控制代碼)用於標識一個進程實際上無權訪問的對象。如果該索引是有效,那麼系統就可以獲得核心對象的資料結構的地址,並可確定該結構中的使用計數的資料成員。如果使用計數是0,該核心便從記憶體中撤消該核心對象。如果將一個無效控制代碼傳遞給C l o s e H a n d l e,將會出現兩種情況之一。如果進程運行正常,C l o s e H a n d l e返回FA L S E,而G e t L a s t E r r o r則返回E R R O R _ I N VA L I D _ H A N D L E。如果進程正在排除錯誤,系統將通知偵錯工具,以便能排除它的錯誤。
       在C l o s e H a n d l e返回之前,它會清除進程的控制代碼表中的項目,該控制代碼現在對你的進程已經無效,不應該試圖使用它。無論核心對象是否已經撤消,都會發生清除操作。當調用C l o s e H a n d l e函數之後,將不再擁有對核心對象的訪問權,不過,如果該對象的使用計數沒有遞減為0,那麼該對象尚未被撤消。這沒有問題,它只是意味著一個或多個其他進程正在使用該對象。當其他進程停止使用該對時(通過調用C l o s e H a n d l e),該對象將被撤消。
            假如忘記調用C l o s e H a n d l e函數,那麼會不會出現記憶體流失呢?答案是可能的,但是也不一定。在進程運行時,進程有可能泄漏資源(如核心對象)。但是,當進程終止運行時,作業系統能夠確保該進程使用的任何資源或全部資源均被釋放,這是有保證的。對於核心對象來說,系統將執行下列操作:當進程終止運行時,系統會自動掃描進程的控制代碼表。如果該表擁有任何無效項目(即在終止進程運行前沒有關閉的對象),系統將關閉這些物件控點。如果這些對象中的任何對象的使用計數降為0,那麼核心便撤消該對象。
            因此,應用程式在運行時有可能泄漏核心對象,但是當進程終止運行時,系統將能確保所有內容均被正確地清除。另外,這個情況適用於所有對象、資源和記憶體塊,也就是說,當進程終止運行時,系統將保證進程不會留下任何對象。

以下是網友的評論:

CreateThread啟動了一個線程,同時產生一個控制代碼讓你好操縱這個線程,如果你不要用這個控制代碼了就CloseHandle關掉它。
調用這個CloseHandle並不意味著結束線程,而是表示不關心此控制代碼的狀態了,也就無法控制子進程的線程了。如果需要關心,可以在子進程結束後再CloseHandle,但一定得CloseHandle。
作業系統核心管理核心對象的生命期,應用程式通過CloseHandle操作核心對象的引用計數,當引用計數由1降為0時,核心負責銷毀相應的核心對象。進程和線程都有一個核心對象與它們對應,作業系統通過核心對象管理進程和線程。

本人總結:

當你在程式中,不需要再操作建立的線程時,就CloseHandle掉,即便是那個線程目前計數為1,等你調用CloseHandle後該計數降為0,但已經建立的線程並沒有被馬上撤消,而是等線程函數執行完畢後才撤消,或者是線上程函數執行完畢前整個進程結束,那麼該線程也被撤消。至於為什麼在計數降為0時,沒有馬上撤消該線程,不是很清楚。

 

今天(2007-08-28)又看了下《Windows核心編程》,有了些新的認識:

6.4:當CreateThread被調用時,系統建立一個線程核心對象。該線程核心對象不是線程本身,而是作業系統用來管理線程的較小的資料結構。………………這與進程和進程核心對象之間的關係是相同的。6.6:調用CreateThread可使系統建立一個線程核心對象。該對象的初始使用計數是2(線上程停止運行和從CreateThread返回的控制代碼關閉之前,線程核心對象不會被撤銷)。

根據最後一條就可以解釋我昨天的疑問了^_^

 

 

——————————————————————————————————————————————

一,在程式中建立線程的概念

      對於一個進程而言,在進程建立後,同時系統也會為進程自動分配一個主線程。拿Main函數而言,當Main函數執行完後,此時主線程就退出了,主線程退出也同時意味著進程結束。

二,線程、核心對象、核心對象引用計數

      1.建立一個線程有幾種方法,這裡我們先學習的是利用CreateThread()函數建立線程,此函數的參數及具體用法參見MSDN。如果建立線程成功,函數則返回一個新的線程控制代碼。(根據《Windows核心編程》,線程建立時,系統設定線程核心對象的引用計數為1,在Create函數返回前,將會開啟線程控制代碼,所以線程的核心對象引用計數+1)

=================================================================================

CreateThread後那個線程的引用計數不是1,而是2。  
   
  creating   a   new   process   causes   the   system   to   create   a   process   kernel   object    
  and   a   thread   kernel   object.   At   creation   time,   the   system   gives   each   object    
  an   initial   usage   count   of   1.   Then,   just   before   CreateProcess   returns,   the    
  function   opens   the   process   object   and   the   thread   object   and   places   the    
  process-relative   handles   for   each   in   the   hProcess   and   hThread   members   of    
  the   PROCESS_INFORMATION   structure.   When   CreateProcess   opens   these   objects    
  internally,   the   usage   count   for   each   becomes   2.                                                  ---摘自《Windows核心編程》

=================================================================================

三,CloseHandle()用法

      1.CloseHandel(ThreadHandle );
只是關閉了一個線程控制代碼對象,表示我不再使用該控制代碼,對該控制代碼不感興趣,即不對這個控制代碼對應的線程做任何幹預了。並沒有結束線程,線程本身還在繼續運行。如果你CreateThread以後需要對這個線程做一些操作,比如改變優先順序,被其他線程等待,強制TermateThread等,就要儲存這個控制代碼,使用完了再CloseHandle()。

      2.為什麼要CreateThread()和CloseHandle()緊挨配套使用

一方面,所有的核心對象(包括線程Handle)都是系統資源,用了要還的,也就是說用完後一定要CloseHandle關閉之,如果不這麼做,你系統的控制代碼資源很快就用光了,另一方面,由於CreateThread()後線程核心對象的引用計數是2,在CloseHandle()引用計數-1之後,核心對象引用計數仍不為0,不會被釋放,所以線程仍運行,直到線程函數執行完畢後,引用計數再-1,線程結束。

還可以查看這篇文章  http://hi.baidu.com/heiheijiushiwo/blog/item/02c29924e518e0318644f979.html

 

啟發:

1 windows 核心編程 以後得看

2 系統管理線程是通過線程內部核心對象的引用計數 當此引用計數為0 時線程被關閉

 當在開始 createthread()建立完線程後線程的引用計數為2

調用closehadle()將只關閉不對線程做操作同時將線程引用計數減1

當線上程執行完畢時 引用計數在減1 正常情況下為 0  線程結束

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.