windows多线程基础(4):关于线程更多知识

再了解一点线程,看下图:


  • 调用CreateThread可以使系统创建一个线程内核对象,其初始引用计数是2(在线程停止运行和CreateThread返回的句柄关闭前,该内核对象都不会关闭)。该内核对象的其他属性也被初始化,暂停计数被设置为1,退出代码为STILL_ACTIVE,该对象设置为未通知状态。
  • 内核对象创建完成之后,系统分配栈的内存。系统将两个值写入新线程堆栈的上端(栈总是从该内存的高地址向低地址建立)。写入栈的第一个值是传递给CreateThread的pvParam参数,然后写入参数pdfStartAddr的值。
  • 每个线程都有其一组CPU寄存器,称为线程上下文,反映了线程上次运行时该线程的CPU寄存器状态,这组CPU寄存器被保存在一个CONTEXT结构中。
  • 指令指针IP和栈指针寄存器是线程上下文中最重要的两个寄存器。当线程内核对象被初始化时,CONTEXT结构的栈指针寄存器被设置为线程栈上用来放置pfnStartAddr的地址,指令指针置为BaseThreadStart的地址中。
  • 当线程初始化完成后,系统看CREATE_SUSPENDED标志是否传递给了CreateThread,若该标志没有传递,则线程内核对象的暂停计数减为0,则线程即处于被调度状态。当线程被执行时,线程的上下文被加载到实际的CPU寄存器中,则线程即可执行代码。

下面是BaseThreadStart的函数执行的基本操作:

VOID BaseThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam)
{
    __try {
        ExitThread((pfnStartAddr)(pvParam));
    }
    __except(UnhandleExceptionFilter(GetExceptionInformation())) {
        ExitProcess(GetExceptionCode());
    }
    // NOTE: We never get here.
}

  • 线程的指令指针被设置为BaseThreadStart,因此线程是从这个函数开始执行的。该函数接收两个参数(但这个函数却不是被别的函数调用的,为什么这么说,是因为CreateThread函数把BaseThreadStart的两个参数从右到左压入栈,IP寄存器被设置为BaseThreadStart的位置,然后开始执行该函数的代码),BaseThreadStart函数认为它是由另外一个函数调用的,因此可以访问两个参数。
  • 需要注意的是,在BaseThreadStart函数中,线程要么调用ExitThread函数,要么调用ExitProcess函数,这意味着线程不会从该函数中退出,线程总是在函数中被撤销(线程消失了,没了)。该函数原型的返回时VOID,而它从来都不返回。

ExitThread函数为什么要这样?

函数返回时要在栈上获取返回地址(返回时,需要知道调用BaseThreadStart函数的代码的位置,以及返回后的局部变量,显然这个位置是不存在的)在哪里的,但是当调用ExitThread时,线程的栈会被系统释放,若是再去访问线程的栈,可能会发生内存违规,所以不存在函数调用的位置,也不存在返回的位置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值