CloseHandle以及内核对象的释放

来源:互联网 发布:fifaonline3合卡软件 编辑:程序博客网 时间:2024/06/06 16:36

转自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,线程结束




0 0