浅尝《Windows核心编程》之 线程的生命历程

 

1.    线程创建之初

在线程被创建的时候(通常是在 _beginThreadex()里面调用了CreateThread()来启动线程),操作系统为这个线程创建了一个线程内核对象,并且给与一定得初值,该对象的初始使用计数是2(在创建进程(CreateProcess),和线程(_beginThreadex)都会是这样的效果,主要的原因是创建内核对象时使用计数器加1,打开内核对象的时候使用计数器加1。在线程停止运行和从C r e a t e T h r e a d返回的句柄关闭之前,线程内核对象不会被撤消,所以一般推荐在不需要线程句柄的情况下,创建完就closehandle,或者让线程自我return之后,手动去CloseHandle这个线程,这样就能够做到将这个内核对象正确清除 )。线程的内核对象的其他属性也被初始化,暂停计数被设置为1,退出代码始终为S T I L L _ A C T I V E0 x 1 0 3),该对象设置为未通知状态。然后系统会去处理CONTEXT结构,为这个线程申请堆栈(由于线程是进程的一部分,所以理所当然的该内存是从进程的地址空间分配而来),系统将在堆栈上写入在_beginThreadex()时传入的函数指针(pfnStartAddrj)和参数(pvParam),sp指向它,另外让ip(程序计数器,指明下一条指令位置的指针)指向位于kernel32.dll中的BaseThreadStart(),这是线程真正开始的地方。“其他CPU寄存器”用于存放线程运行时的cpu寄存器的状态,以便在被调出之后再被调回能够找到刚才的处理的结果,然后继续下一步处理。整个结果如下图

 

 

2.    线程被调度执行和消亡

一旦暂停次数为0(如果在create的时候没有加入CREATE_SUSPENDED,系统会在初始化内核对象后将暂停次数递减到0,其他的办法可以运用ResumeThread()方法,或者系统调度的结果),就表示这个线程处于可调度状态。如果可以给这个线程CPU了,就用上次保存的线程上下文中的值(当线程被调出时,就会保存这一系列的值)加载到实际的CPU寄存器中,这样这个线程就可以执行代码了。

第一次调度的时候,由于新线程的指令指针(IP)被置为B a s e T h r e a d S t a r t,因此该函数实际上是线程开始执行的地方。注意他的参数。线程真正的执行实在语句pfnStartAddr(pvParam)这里开始的,直到线程自己return了,才会调用B a s e T h r e a d S t a r t里的ExitThread。注意,根据B a s e T h r e a d S t a r t的代码,我们发现如果某一个线程出现了异常,就会调用ExitProcess,退出整个进程。

posted @ 2009-06-07 11:57  aicro  阅读(454)  评论(2编辑  收藏  举报