线程组成两部分:
1. 一个线程的内核对象,操作系统用它管理线程。
2. 一个线程栈,用于维护线程执行时所需的所有函数参数和局部变量。
何时创建线程?举例:
操作系统的Windows Indexing Services,磁盘碎片整理程序等,都是使用多线程进行性能优化的例子。
线程内幕:
线程的上下文context对象 ,用于线程的调度,如下这张图详细的介绍,线程内核对象以及线程的地址空间,从而知道线程执行原理。
线程内核对象 线程栈
线程创建时,会先创建一个线程内核对象(分配在进程的地址空间上),如上图,存储上下文context(一个数据结构)及一些统计信息,具体包括:
1.寄存器SP:指向栈中线程函数指针的地址
2.寄存器IP:指向装载的NTDLL.dll里RtlUserThreadStart函数地址
3.Usage Count:引用计数,初始化为2
4.Suspend Count:挂起数,初始化为1。
5.ExitCode:退出代码,线程在运行时为STILL_ACTIVE(且初始化为该值)
6.Signaled:初始化为未触发状态
首先看下线程的调度:每个线程都有一个CONTEXT结构,保存在线程内核对象中。大约每隔20ms windows就会查看所有当前存在的线程内核对象。并在可调度的线程内核对象中选择一个,将其保存在CONTEXT结构的值载入cpu寄存器。这被称为上下文切换。大约又过20ms windows将当前cpu寄存器存回内核对象,线程被挂起。Windows再次检查内核对象,并在可调度的内核对象中选择一个进行调度。此过程不断重复直到系统关闭。Windows被称为抢占式多线程系统,系统可以在任何时刻停止一个线程而另行调度另外一个线程。我们对此可以有一些控制,但是权限很小。我们无法保证线程总在运行或者获得整个处理器。当然Windows提供很多API函数用于线程的挂起和恢复,睡眠,切换等。当然为了能够统计一个算法的执行时间,可以开启一个线程采用一些API函数精确统计去除线程切换而损失的时间。
其次分析一下CONTEXT结构以及如何获取和设置上下文CONTEXT结构:
CONTEXT结构包括以下部分:
CONTEXT_CONTROL:包含CPU的控制寄存器,比如指今指针,堆栈指针,标志和函数返回地址..AX, BX, CX, DX, SI, D
CONTEXT_INTEGER:用于标识CPU的整数寄存器.DS, ES, FS, GS
CONTEXT_FLOATING_POINT:用于标识CPU的浮点寄存器.
CONTEXT_SEGMENTS:用于标识CPU的段寄存器.SS:SP, CS:IP, FLAGS, BP
CONTEXT_DEBUG_REGISTER:用于标识CPU的调试寄存器.
CONTEXT_EXTENDED_REGISTERS:用于标识CPU的扩展寄存器I
CONTEXT_FULL:相当于CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS,即这三个标志的组合