CloseHandle以及內核對象的釋放

轉自http://blog.csdn.net/a102111/article/details/8501620

函數說明

BOOL CloseHandle(HANDLE hObject);
參數
hObject :代表一個已打開對象handle。
返回值
TRUE:執行成功;
FALSE:執行失敗,可以調用GetLastError()獲知失敗原因。


函數用於關閉一個內核對象。


CloseHandle到底做了什麼?

當調用CloseHandle成功後,相關的內核對象的引用計數被減1。

這個函數做的工作就這麼多。它並沒有真正的關閉內核對象,只是將計數減1,也就是說,這個時候,如果這個內核對象的引用計數不爲0的話,內核對象依然存在,如果你有辦法找到他,那麼你依然可以操作他。

一個比較常見的問題:

CreateThread後立即CloseHandle,爲什麼線程還在運行?

可以這樣認爲,CreateThread之後,線程的內核對象的引用計數爲2,CloseHandle之後,如果線程還沒有結束,那麼他的引用計數是1,不是0,此時,系統不會回收內核對象,所以線程還在執行。直到線程執行結束,引用計數變成了0,此時,系統回收。

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.

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

創建新的進程後,記數初始化爲1,而函數需要返回進程內核對象的句柄,相當於打開一次新創建的類覈對象,記數再加1。


每次createthread()創建線程對象的時候,線程對象中Usage count的初始化值爲2(注意不是1)
closehandle()能是Usage count的值減少1,這個時候Usage count的值爲1,所以並沒有銷燬,只有
當線程執行的函數通過return結束的時候,Usage count繼續減少1變爲0,這個時候才真正的銷燬對象


內核對象什麼時候被刪除?

以下兩種情況,內核對象會被刪除--系統回收:

  1. 當內核對象的引用計數爲0的時候
  2. 進程結束
如果內核對象的引用計數不爲0,但是相關的進程都已經結束了,那麼該內核對象會被系統回收
參考:
進程確實沒有機會執行自己的清除操作,但是操作系統可以在進程之後進行全面的清除,使得所有操作系統資源都不會保留下來。這意味着進程使用的所有內存均被釋放,所有打開的文件全部關閉,所有內核對象的使用計數均被遞減,同時所有的用戶對象和GDI對象均被撤消。
       ----摘自Windows核心編程 第四版 4.3.3


內核對象泄露

內核對象在使用完畢之後,沒有及時調用CloseHandle關閉,在該進程運行期間,將造成內核對象泄露

內核對象泄露會對系統造成一定程度的負面影響,但進程結束退出後,操作系統會自動回收這些內核對象。


//

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

      對於一個進程而言,在進程建立後,同時系統也會爲進程自動分配一個主線程。拿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,線程結束




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章