關于CreadThread()與CloseHandle()
今天看了點關于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 線程結束
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成