什么是句柄:
句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?
为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。
句柄地址(稳定)→记载着对象在内存中的地址→对象在内存中的地址(不稳定)→实际对象
线程与线程句柄的关系:
句柄可以认为是系统对资源(如线程)的分配的一个编号。关闭这个编号,对于不同的资源,效果不尽相同。对于线程来说,关闭这个编号并不意味着终止线程,只是之后很难再操纵这个线程。
线程句柄与线程ID的区别:
CreateThread() API 用于创建线程。 API 返回同时线程句柄和线程标识符 (ID)。线程句柄有完全访问权创建线程对象。 运行线程时线程 ID 唯一标识线程在系统级别。
●ID是在Windows系统范围内唯一标示Thread的。 
●Handle是用来操作Thread的,可以有多个,每个HANDLE可以有不同的操作权限,在不同进程OpenThread得到的值不一样。 
●线程的ID是系统全局的,其HANDLE是进程局部的.

●此ID只在线程的生存期内有效。

●HANDLE是os和client之间用来操作进程和线程一个桥梁,os有一张维护HANDLE的表单,里面大概放置了 HANDLE的引用计数和有关的属性,HANDLE是os标识进程和线程的东西,但是用户也可以用这个来标识进程和线程,对其操作;而ID是os用来标识进程和线程的,并且是全局唯一的, 但用户可以通过这个ID获得进程线程的HANDLE,多次得到的HANDLE并不一定是一样的.HANDLE是内核对象,而ID好像不是,并没有专门创建ID的函数.

●ID是CreateThread时操作系统自动生成的。

●线程的句柄和id是不同的。 
在windows系统中,线程的id是唯一对应的,也就是说,如果两个线程返回相同的id,则他们必然是同一线程,反之一定是不同的线程。而线程的句柄并不是线程的唯一标识,线程的句柄只是用来访问该线程的的一个32位值,尽管相同的句柄一定标识同一线程,但同一线程可能拥有两个打开的句柄,因此,不能用句柄来区分两个线程是否是同一线程。
线程终止运行时发生的操作
  当线程终止运行时,会发生下列操作:
  • 线程拥有的所有用户对象均被释放。在 Windows 中,大多数对象是由包含创建这些对象的线程的进程拥有的。但是一个线程拥有两个用户对象,即窗口和挂钩。当线程终止运行时,系统会自动撤消任何窗口,并且卸载线程创建的或安装的任何挂钩。其他对象只有在拥有线程的进程终止运行时才被撤消。
  • 线程的退出代码从 STILL_ACTIVE 改为传递给 ExitThread 或 TerminateThread 的代码。
  • 线程内核对象的状态变为已通知。
  • 如果线程是进程中最后一个活动线程,系统也将进程视为已经终止运行。
  • 线程内核对象的使用计数递减 1。
  当一个线程终止运行时,在与它相关联的线程内核对象的所有未结束的引用关闭之前,该内核对象不会自动被释放。
  一旦线程不再运行,系统中就没有别的线程能够处理该线程的句柄。然而别的线程可以调用 GetExitcodeThread 来检查由 hThread 标识的线程是否已经终止运行。如果它已经终止运行,则确定它的退出代码:
  BOOL GetExitCodeThread(HANDLE hThread, PDOWRD pdwExitCode);
  退出代码的值在 pdwExitCode 指向的 DWORD 中返回。如果调用 GetExitCodeThread 时线程尚未终止运行,该函数就用 STILL_ACTIVE 标识符(定义为 0x103)填入 DWORD。如果该函数运行成功,便返回 TRUE。

线程退出的时候内核对象就会被激发, WaitForSingleObject()为堵塞函数,等待线程的内核对象被激发。所以终止线程并释放句柄对象的顺序是:TerminateThread()-->WaitForSingleObject()-->CloseHandle().

线程、线程句柄、线程ID的生成和消失

hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwId);

//至此,新线程,线程句柄,线程ID产生

TerminateThread(hThread, 0);
//至此,线程ID,线程句柄都依然存在

WaitForSingleObject(hThread, INFINITE);

//至此,线程本身和线程ID消失

CloseHandle(hThread);
//至此,线程句柄消失

线程、线程句柄、线程ID的更多相关文章

  1. EPROCESS 进程/线程优先级 句柄表 GDT LDT 页表 《寒江独钓》内核学习笔记(2)

    在学习笔记(1)中,我们学习了IRP的数据结构的相关知识,接下来我们继续来学习内核中很重要的另一批数据结构: EPROCESS/KPROCESS/PEB.把它们放到一起是因为这三个数据结构及其外延和w ...

  2. 线程的2个ID

    我们知道进程ID是操作系统调度的最小单位,有时候根据业务的需要,我们会使用到多线程技术,当创建了多个线程时,也会有一个线程ID,那这个线程ID和进程ID有什么不一样吗? 其中,线程组的线程ID是属于N ...

  3. 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。如:ABCABCABC…… 依次递归

    import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.uti ...

  4. python启动线程查看线程的名称和id;python杀掉进程的方法

    def cpu_app(): print("CPU") #启动一个线程t=threading.Thread(target=cpu_app,args=()) t.daemon = T ...

  5. IOS 线程处理 子线程

    IOS 线程处理 子线程的启动与结束 技术交流新QQ群:414971585   IOS中,如果要在主线程中启动一个子线程,可以又两种方法: [NSThread detachNewThreadSelec ...

  6. Windows线程漫谈界面线程和工作者线程

    每个系统都有线程,而线程的最重要的作用就是并行处理,提高软件的并发率.针对界面来说,还能提高界面的响应力. 线程分为界面线程和工作者线程,界面实际就是一个线程画出来的东西,这个线程维护一个“消息队列” ...

  7. C# 线程--第四线程实例

    概述 在前面几节中和大家分享了线程的一些基础使用方法,本章结合之前的分享来编写一些日常开发中应用实例,和编写多线程时一些注意点.如大家有好的实例也欢迎分享.. 应用实例 应用:定时任务程序 场景:系统 ...

  8. C# 线程--第三线程池

    概述 线程池有那些优点: 1.在多线程中线程池可以减少我们创建线程,并合理的复用线程池中的线程.因为在线程池中有线程的线程处于等待分配任务状态. 2.不必管理和维护生存周期短暂的线程,不用在创建时为其 ...

  9. Java并发——线程安全、线程同步、线程通信

    线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...

  10. 新建线程与UI线程间的通信

    现在用一个实例来演示一下自己的新建线程与UI线程间的通信. UI界面包含3个控件: 一个输入框,用来输入数字: 一个显示框,用来显示从2开始,到输入数字之间的所有质数: 一个按钮,点击后获取输入框输入 ...

随机推荐

  1. Nginx常见502错误

    1.配置错误因为nginx找不到php-fpm了,所以报错,一般是fastcgi_pass后面的路径配置错误了,后面可以是socket或者是ip:port2.资源耗尽lnmp架构在处理php时,ngi ...

  2. js库编写的环境和准备工作

    在编写一个js库之前需要准备许多基础知识. 本人在编写之前主要参考了visjs和百度的echarts这两个库的部分内容,这之中提取出几个要点如下: 1.如何整理代码结构,使模块与模块分开又不至于出现调 ...

  3. MVC 5 下,应用log4net收集异常信息

    1.安装log4net. 首先在VS中通过nuget安装logenet,我用的是VS2013,截屏如下:

  4. 让 asp.net mvc 支持 带有+ _ 等特殊字符的路由

    最近配置微信 业务域名 时,需要在服务器的根目录中上传一个文本文件,而这个文本文件需要放这样的目录中: 于在就在 服务器目录中创建了对应的文件夹,并将kuPv.txt上传,但是访问时,却怎么也访问不到 ...

  5. 浅谈MDX处理空值NULL及格式化结果

    MDX查询结果中往往会含有"NULL"值,这是某维度下对应的的量值不存在导致的,为了让报表呈现更好的效果,在有些情况下,需要将"NULL"的切片值置换成0,这些 ...

  6. 使用DataSet数据集插入记录

    使用INSERT语句能够完成数据插入,使用DataSet对象也可以完成数据插入.为了将数据库的数据填充到DataSet中,则必须先使用DataAdapter对象的方法实现填充,当数据填充完成后,开发人 ...

  7. net.sf.json.JSONException: There is a cycle in the hierarchy!

    因为项目中使用了AJAX技术,jar包为:json-lib.jar,在开发过程中遇到了一个JSON-LIB和Hibernate有关的问题: 如hibernate延迟加载错误,这都是些老问题了,一看就知 ...

  8. js判断一个变量是否为数组的解决方案

    前端开发中,在做项目的时候,我们经常需要对一个变量进行数组类型的判断,当然即使你暂时没遇到,但是这个问题也是大家去面试时的高频问题,有必要拿出来说一说. 大家都知道js中可以使用typeof来判断变量 ...

  9. Jquery实现日期格式化

    格式一:yyyy-MM-dd HH:mm:ss Date.prototype.format = function(format) { /* * eg:format="yyyy-MM-dd h ...

  10. 转发细节——forward

    1)forward()方法之前的输出,如果是输出到缓冲区,再转发到其它Servlet,那么原缓冲区的数据忽略不计:2)forward()方法之前的输出,如果真正输出到浏览器,再转发到其它Servlet ...