Windows学习(008)--线程(二)

来源:互联网 发布:eclipse怎么写sql语句 编辑:程序博客网 时间:2024/06/14 15:24

线程启动到死亡

  1. 创建线程的内核对象
    • 使用计数,为2
    • 暂停计数,是一个UINT类型,这就意味着,一个线程会被暂停多次,当暂停计数为0时,这个线程才将会被执行,为1
    • 退出代码,此时的退出代码为STILL_ACTIVE
    • Signaled,开始为FALSE

    • 在栈顶会有lpParam和lpfnAddr
  2. CONTEXT线程上下文结构体,线程上一次运行时的寄存器

    • EIP(指令寄存器),指示下一条代码在哪运行,最开始会指向RtlUesrThreadStart(未公开的函数),当调用CreatrThread函数时,CreatrThread会去调用RtlUesrThreadStart函数
    • ESP(栈寄存器),指向栈顶,也就是lpfnAddr
  3. 暂停计数减1,为0后,交给CPU调度

  4. RtlUesrThreadStart

    • 设置一个结构化异常SEH
    • 调用线程函数,lpParam传入进去
    • 等待线程的返回
    • 当函数返回时,会调用ExitThread,并把线程函数的返回值给ExitThread函数
    • 使用计数减1

_beginthreadex和CreateThread

  1. _beginthreadex,在process.h头文件中,属于纯C/C++多线程运行库

        uintptr_t _beginthreadex( // MANAGED CODE      void *security,      unsigned stack_size,      unsigned ( __clrcall *start_address )( void * ),      void *arglist,      unsigned initflag,      unsigned *thrdaddr );
  2. _beginthreadex使一些非线程安全的函数变安全,将非线程函数写到线程里面,使这些函数从全局的任何线程可以访问的,变成了当前线程独有的,其基本原理是将一些非线程安全函数的数据结构放到当前线程的堆里

  3. 相较于CreateThread,_beginthreadex多开辟了一块空间,分配的堆上的,用来存储C语言的这些全局变量,使这些全局变量变得安全,然后它就会去调用CreateThread

  4. _endthreadex,用来释放_beginthreadex中分配的空间

    void _endthreadex(    unsigned retval );

线程状态

  1. 启动
    • CONTEXT
    • 使用计数=2
    • 暂停计数 = 1,整个线程创建完成后,-1,为0,进入CPU调度, 当前线程是可执行的状态
  2. 运行
    • 执行我们的函数->时不时切换我们的线程->切换后会将写入CONTEXT->等待其它线程执行->读取CONTEXT->执行我们的函数->…
  3. 挂起

    • 会将线程中的暂停计数+1,暂停线程的执行,暂停后CPU就不会分配时间片给线程
    • 挂起函数SuspendThread,等待当前函数的时间片被知行完后,再挂起线程
    DWORDWINAPISuspendThread(_In_ HANDLE hThread);
    • 恢复挂起函数
    DWORDWINAPIResumeThread(_In_ HANDLE hThread);
    • 不推荐线程挂起
  4. 等待/ 休眠

    • Sleep
        VOID WINAPI Sleep(  _In_ DWORD dwMilliseconds);
    • Sleep(100),休眠100毫秒,实际上不是真正的100毫秒,无限接近100毫秒
      • 线程是非实时的,在100毫秒之后,CPU时间片如果在执行其它的线程,那么等这个时间片执行后,才会有可能分配时间片给这个等待100毫秒后的线程
      • 当调用Sleep,该线程会放弃当前时间片
    • SwitchToThread

          BOOL WINAPI SwitchToThread(void);

      当前线程放弃时间片,并把这些时间片交给饥饿度高的线程

  5. 消亡
原创粉丝点击