创建线程的内幕(6)

本文深入探讨了Windows系统中创建线程的过程,包括线程内核对象的初始化、堆栈分配、线程上下文的设置,以及RtlUserThreadStart函数在其中的作用。线程的执行从RtlUserThreadStart开始,涉及结构化异常处理、线程函数调用及退出流程。主线程的启动类似,但由C/C++运行库启动代码控制,最终调用ExitProcess。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      当调用CreateThread函数后,线程内核对象的使用计数初始化为2,暂停计数被初始化为1,退出代码被设为STILL_ACTIVE(0x103),并且对象被设为未触发状态。

      一旦创建线程内核对象,系统便分配内存,供线程堆栈使用。此内存是从进程地址空间内分配的,线程没有自己的地址空间。然后系统将CreateThread函数传入的pvParam参数值放入堆栈最上端,紧接着它下方是pfnStartAddr参数的值。

      每个线程都有自己的一组cpu寄存器,称为线程上下文。其反应线程上一次执行时的cpu寄存器状态。cpu寄存器状态保存在一个CONTEXT结构中,CONTEXT结构本身保存在线程内核对象中。


      当线程内核对象初始化的时候,CONTEXT结构中的堆栈指针寄存器被设为pfnStartAddr在线程堆栈中的地址。而指令指针寄存器被设为RtlUserThreadStart函数(此函数是NTDLL.dll导出的)的地址。

      当初始化完成后,系统会检查CREATE_SUSPENDED标识是否已被传给CreateThread函数,如果没有传递,系统将线程的挂起技术递减至0;随后,线程就可以调度给一个处理器去执行了。然后,系统在实际的cpu寄存器中加载上一次在线程context中保存的值。现在,线程可以在其进程的地址空间中执行代码并处理数据了。


      RtlUserThreadStart函数是线程的实际开始执行的函数。新线程执行RtlUserThreadStart函数时,将发生:

         1.设置一个结构化异常处理帧(SEH)。P159

         2.系统调用线程函数。

         3.线程函数返回时,RtlUserThreadStart调用ExitThread,将你的线程函数的返回值传给它。线程内核对象计数递减,而后线程停止执行。

         4.如果线程产生了一个未被处理的异常,RtlUserThreadStart函数所设置的SEH会处理这个异常。通常会发出一个消息提醒框,当用户关闭框时,RtlUserThreadStart会调用              ExitProcess来终止整个进程,而不是终止有问题的线程。

      注意,在RtlUserThreadStart函数内,线程会调用“ExitThread”和“ExitProcess”。说明线程永远不能退出此函数;始终在其内部消亡。所以RtlUserThreadStart返回值为VOID(因为它永远不会返回)。如果在没有强行“杀死”线程的情况下尝试返回,它会返回随机位置(因为线程堆栈上没有函数返回地址),这会引起违规操作。【线程被包裹在RtlThreadStart函数之内】

      


       进程的主线程在初始化时,其指令指针会被设为同一个未文档化的RtlUserThreadStart。当RtlUserThreadStart开始执行时,它会调用C/C++运行库启动代码,后者继而调用你的_tmain函数或_tWinMain函数。你的入口点函数返回,运行库启动代码调用ExitProcess。所以对于主线程而言,主线程永远不会返回到RtlUserThreadStart函数。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值