Windows核心编程读书笔记2——线程(2)线程内幕

线程结构

如上一篇文章所述,系统创建线程时,会分配一个内核对象与线程栈。如下图


线程内核对象如图左侧,其初始为

1、引用计数为2

2、挂起计数为1(此时线程无法运行,当线程初始化好后,若未设置CREATE_SUSPENDED标志,则系统会自动将挂起计数减至0,线程为可调度状态)

3、退出代码为STILL_ACTIVE状态

4、内核对象未触发状态

5、记录线程上下文的CONTEXT结构为初始值(所谓线程切换,其实就是根据CONTEXT结构数据更新CPU寄存器内容)。注意其中的SP(栈指针寄存器)与IP(指令指针寄存器)。

SP指向pfnStartAddr而IP指向NTDLL.dll导出的

RtlUserThreadStart函数。这说明,其实每个新建的线程,其运行入口并不是我们传入的线程函数,而是统一会由系统调用RtlUserThreadStart

RtlUserThreadStart函数定义如下

VOID RtlUserStartThread(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParm)
{
    __try
    {
        ExitThread((pfnStartAddr)(pvParm));
    }
    __except(UnhandledExceptionFilter(GetExceptionInformation()))
    {
        ExitProcess(GetExceptionCode());
    }
    // Note: We never get here
}

观察RtlUserThreadStart函数,可得到如下事实:

1、RtlUserThreadStart函数最终调用ExitThread函数退出线程并设置退出码。

2、若线程运行期由任何异常,则会被捕获并结束整个进程。

3、RtlUserThreadStart只会被操作系统调用来开启线程。

4、RtlUserThreadStart会为线程的返回地址压栈,让线程可返回。但RtlUserThreadStart本身永远不会返回,因为在函数返回前,其线程已经结束(如代码中注释一样)。

5、当进程运行主线程时,RtlUserThreadStart会调用C/C++的运行库启动代码,并有启动代码调用main函数,当线程由main返回时,C/C++启动代码会调用ExitProcess退出进程。

线程栈如图右侧所示。

1、线程栈空间来自进程空间。

2、线程栈空间由高向低扩展。

3、线程栈系统会默认写入两个值,分别是CreateThread时传入的线程参数与线程函数地址。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值