1,线程和线程句柄(Handle)不同,线程是一个程序的工作流程,线程句柄是一个内核对象。线程的生命周期就是线程函数从开始执行到线程结束,线程句柄一旦CreateThread返回,如果你不用它操作线程或者等待线程等操作比如waitforsingleobject,就可以CloseHandle。

(ps:对于线程来讲,如果线程在运行状态则为无信号状态,在退出后为有信号状态。所以我们可以使用 WaitForSingleObject 来等待线程退出)

2,CreateThread以后需要对这个线程做一些操作,比如改变优先级,被其他线程等待,强制TermateThread等,就要保存这个句柄,使用完了再操作CloseHandle。

3、CloseHandle只是关闭了一个线程句柄对象,表示我不再使用该句柄,即不对这个句柄对应的线程做任何干预了,和结束线程没有一点关系。若在线程执行完之后,没有调用CloseHandle,在进程执行期间,将会造成内核对象的泄露,相当于句柄泄露,但不同于内存泄露,这势必会对系统的效率带来一定程度上的负面影响。但当进程结束退出后,系统会自动清理这些资源。

4、关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。

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

今天看了点关于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,线程结束。

启发:

1 windows 核心编程 以后得看

2 系统管理线程是通过线程内部内核对象的引用计数 当此引用计数为0 时线程被关闭

当在开始 createthread()创建完线程后线程的引用计数为2

调用closehadle()将只关闭不对线程做操作同时将线程引用计数减1

当在线程执行完毕时 引用计数在减1 正常情况下为 0  线程结束

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

关于线程与线程句柄

主线程只要拥有线程句柄,事后就可以对线程执行某些操作,比如查询线程状态等等,靠的就是句柄,如果没有句柄,系统就无从知道要查的是那个线程的状态。但保持这个句柄不关闭,并不是线程运行的条件。

关闭线程句柄只是释放句柄资源,新开启线程后,如果不再利用其句柄,应该关闭句柄,释放系统资源。关闭线程句柄和线程的结束与否没有关系。

句柄可以认为是系统对资源(如线程)的分配的一个编号。关闭这个编号,对于不同的资源,效果不尽相同。对于线程来说,关闭这个编号并不意味着终止线程,只是之后很难再操纵这个线程。   这就好比摘掉了门牌号,并不伤害这一家人,只是以后往这送信就麻烦些了。   还有,如果主线程只想创建线程,而并不想之后再查询或操纵它,那么及时关闭句柄是个好习惯,免得当时没关,以后又忘了,于是泄漏了系统的句柄资源(系统句柄总数是有限的)。

如果知道引用计数是怎么回事就很好解释了。   CloseHandle(hThread)   只是减去一个hThread的引用计数。

线程句柄就像你家的地址,线程就像你的家房子,   你说如果没有了你家的地址,难道就没有你家的房子了吗?   线程与线程句柄也是一样的道理,句柄只是可以对这个线程作一些操作。

CloseHandle是关闭线程句柄,用来释放线程资源的,不是终止线程的.线程的终止用terminatethread或exitthread,TerminateThread的使用会导致各类资源释放问题,主要是与该线程相连的各类dll,他们无法得到线程退出的通知。应该在线程中自然退出(即隐式调用ExitThread)或直接显式调用ExitThread。退出的时机应由同步对象或其他机制来实现,而且主线程一般应使用WaitForSingleObject函数等待该线程的句柄,以确保线程的退出。 希望对你有帮助

线程句柄以及createthread()和closehadle()相关推荐

  1. C++ 使用_beginthreadex创建线程、线程句柄(等待线程关闭)、线程id的作用(发送线程消息)

    _beginthreadex c语言库 process.h 中的函数, 用来创建一个线程 unsigned long _beginthreadex(       void *security,     ...

  2. c++ 多线程:线程句柄可以提前关闭,但是线程并没有关闭

    很多程序在创建线程都这样写的: ThreadHandle = CreateThread(NULL,0,.....); CloseHandel(ThreadHandle ); 1,线程和线程句柄(Han ...

  3. Win32下对多个的线程句柄的关闭的控制(上)

    网上看到自己04年发表在CSDN上的文章,当时还上了首页.现在看来蛮幼稚的,很有趣:当时应该没有blog这种东东,现在发表到blog上,纪念一下逝去的青春. --------------------- ...

  4. Windows线程同步、CreateThread与_beginthread的区别

    进程与线程的区别 一个exe是可执行程序文件,文件被系统加载到内存并将相关资源(比如内存.文件)准备好,并在内存中开始运行后,此时叫做一个进程.进程进行的是负责与操作系统资源的协调,进程所需要的资源在 ...

  5. Win64 驱动内核编程-11.回调监控进线程句柄操作

    无HOOK监控进线程句柄操作 在 NT5 平台下,要监控进线程句柄的操作. 通常要挂钩三个API:NtOpenProcess.NtOpenThread.NtDuplicateObject.但是在 VI ...

  6. 创建线程的函数CreateThread

    主线程的进入点函数的名字必须是main.main.WinMain或wWinMain,其它线程必须用不同的名字 主线程的进入点函数传递了字符串参数,因此可以使用 ANSI/Unicode版本的进入点函数 ...

  7. java 线程句柄_关于多个的线程操作文件 文件句柄(java中得文件流)

    //审批基本信息 public static Map writeBasicToMap(Class gcprojcheckupClas,String fileDirPath,Map map) throw ...

  8. 易语言远程线程注入DLL到游戏

    远程线程注入CreateRemoteThread通过获取注入目标进程的句柄,把我们的DLL注入到目标进程内存地址,远程线程的意思是另一个进程中的线程,并非远控的意思,也就是远程线程注入是指一个进程在另 ...

  9. cjson调用的实例 c++

    主类中文定义 #include <QtGui/QApplication> #include <QTextCodec>QTextCodec::setCodecForTr(QTex ...

最新文章

  1. ACdream 1099——瑶瑶的第K大——————【快排舍半,输入外挂】
  2. 奖牌分配/Median Pyramid Hard
  3. 解决fatal: No remote repository specified. Please, specify either a URL...
  4. php socket 效率,php socket 模型及效率问题
  5. delphi使用 第三方控件
  6. sql java驱动程序_Microsoft SQL Server JDBC 驱动程序支持矩阵
  7. unity3d 任务头上的血条
  8. Linux文件系统十问
  9. 原子自增_小学妹教你并发编程的三大特性:原子性、可见性、有序性
  10. Shell 概述、截取字符操作等
  11. eclipse 中提示tomcat 的端口被占用了 后的最快捷解决方法
  12. Andromeda OS 来了,Android 再见?
  13. Vue 2.0 + Axios + Vue Router 实现CNode社区
  14. uni-app项目部署 打包 运行
  15. zip和rar压缩文件的区别
  16. 2-1 组合优化问题
  17. MyBatis是如何自动装配的
  18. 项目管理知识体系指南(六)项目成本管理
  19. 【查缺补漏】工作中遇到的问题集锦01
  20. 积分无法积,用估值后再使用连续函数介值定理_20160430

热门文章

  1. 前端面试题-clearfix(清除浮动)
  2. 转:Lora重要知识
  3. 程序、进程、线程的概念
  4. 解决elasticsearch主分片unassigned的问题
  5. Flink SQL·validate
  6. python进程池-共享数据
  7. 【Shiro权限管理】5. Shiro权限URL 配置细节
  8. dropwizard中上传和下载文件
  9. 图嵌入前篇之词嵌入模型 Wrod2Vec
  10. 【老生谈算法】matlab十进制转换十六进制及互转