Windows线程启动和消亡详解

来源:互联网 发布:淘宝退货申请假冒品牌 编辑:程序博客网 时间:2024/06/03 13:39

线程的创建:前提条件,线程的创建是在某一个进程当中调用CreateThread()创建一个线程。


线程的创建:

No.1:创建内核对象。

1.使用计数:设置使用计数+1,当一个线程被创建的时候,线程内核的使用计数会加1.

2.暂停计数:设置暂停计数,这个参数是一个UINT 类型的,这就代表着这个线程可以被多次的暂停。当一个线程被创建出来的时候,暂停计数是1的状态,只有当暂停计数为0的时 线程才会启动。

3.退出代码:线程初始化启动时候线程的退出代码会被设置成STILL_ACTIVE。

4.信号(Signaled):线程的信号会被设置成False。

5.CONTEXT:在线程刚被创建的时候就会创建一个线程的上下文的结构体,但是在这里它还没有被初始化。


No.2:设置栈

线程创建到这一步的时候,会去线程所在的进程内申请一块空间,给我们的栈使用。然后lpParam(线程传递参数)和 lpfnAddr(线程入口函数)这两个参数会被压入线程入口处去的前两个栈中。


No.3:CONTEXT:

在有了栈空间的情况下, 接下来就会初始化我们的CONTEXT,CONTEXT是保存了线程在上一次运行时CPU寄存器的状态。

这里重点说明一下EIP和ESP寄存器在的状态。

EIP(指令寄存器):会调用Void RtlUserThreadStart(lpParam,lpfnAddr)这个函数,这个函数是个未公开的函数。这个函数分别接受这两个参数。

ESP(栈寄存器):ESP会指向lpfnAddr。也就是栈顶的位置。

这里要说明下线程的切换->线程的切换其实就是在切换问题。线程的切换其实就是在切换CONTEXT线程的上下文。当CONTEXT被切换的时候,会先将CONTEXT里面的内容加载物理寄存器当中,物理寄存器会根据EIP指令寄存器来进行代码的执行。


NO.4:CPU调用

当CONTEXT也被初始化了之后,这里就进入到了CPU的调用阶段。调用之前,会检查线程是否被设置成暂停状态,如果线程没有被设置成暂停状态,那么,就会将线程的暂停计数-1,然后执行线程。

消亡:

No.5:调用RtlUserThreadStart

1.创建一个管理异常的结构体SEH。

2.调用线程函数,CreateThread是在RtlUserThreadStart中被调用的,并且将lpParam这个参数传递进去。

3.等待线程函数的返回值。

4.调用ExitThread,这个时候,线程的内核使用计数就会递减。


小结:由上面的叙述可知,线程的启动和消亡的整个过程中,RtlUserThreadStart,和CONTEXT这两个东西起到了很重要的作用。整个线程的调用和消亡来自RtlUserThreadStart,线程的运行代码和当前运行状态都保存在CONTEXT当中。