基础知识:如下所示:
1.不同的应用程序会分配成不同的进程(一个虚拟地址空间)。一个进程中使用的代码和数据无法被另一个进程访问,从而确保应用程序的健壮性(可靠性)。
2.一个进程中可以分配多个线程,且不同进程的线程之间互相独立。当一个进程中的线程被冻结时,其他进程的线程可以正常执行,从而确保应用程序的响应能力。
3.线程的数量不超过CPU数目时,线程可以全速运行;否则就会出现上下文切换和性能损失。
4.构造Thread对象是轻量级的操作,因为它并不实际创造一个操作系统线程。要实际创造操作系统线程,并让它开始执行回调函数,必须调用Thread的Start函数,向它传递要作为回调函数的实参传递的对象。
线程内存开销:如下所示:
1.线程内核对象:OS创建线程时都会分配并初始化的内存块。具有以下部分:
1>.一组对线程进行描述的属性。
2>.线程上下文。x86架构占用700KB;x64架构占用1240KB;arm架构占用350KB。
2.线程环境块:是在用户模式(应用程序代码能快速访问的地址空间)中分配并初始化的内存块。具有以下部分:
1>.包含一个4KB的内存页。
2>.包含线程的异常处理链首。线程进入try块都会在链首插入一个节点;线程退出try块时都会从链首删除该节点。
3>.线程本地存储以及GDI和OpenGL数据结构。
3.用户模式栈:一个1MB的内存块。具有以下部分:
1>.存储传给函数的局部变量和实参。
2>.包含一个地址。指出当前函数返回时,线程应该从什么地方接着执行。
4.内核模式栈:一个12KB(32位OS)或者24KB(64位OS)的内存块。具有以下特性:
1>.针对从用户模式的代码传给内核的任何实参,OS都会从线程的用户模式栈复制到线程的内核模式栈。
2>.内核会调用它自己内部的函数,并利用内核模式栈传递它自己的实参,存储函数的局部变量以及存储返回地址。
线程时间开销:如下所示:
1.DLL线程连接和线程分离通知:创建线程时,所有非托管DLL的DllMain函数会收到DLL
_THREAD_ATTACH通知;终止线程时,所有非托管DLL的DllMain函数会收到DLL
_THREAD_DETACH通知。
2.上下文切换:是一种净开销操作,但是可以给用户提供一个健康且响应灵敏的OS。流程如下所示:
1>.将CPU寄存器的值保存到当前正在运行的线程的内核对象内部的一个上下文结构中。
2>.从现有线程集合中选出一个线程供调度。
3>.将所选上下文结构中的值加载到CPU的寄存器中。
线程优先级:每个线程都分配了从0(最低)到31(最高)的优先级。具有以下特性:
1.进程优先级类从低到高依次为:Idle,Below Normal,Normal,Above Normal,High和Realtime。
2.相对线程优先级从低到高依次为:Idle,Lowest,Below Normal,Normal,Above Normal,Highest和Time-Critical。
3.系统启动时会创建一个特殊的零页线程。该线程的优先级为0,并会在其他线程没有工作的时候将系统RAM的所有空闲页清零。
4.内核模式下运行的设备驱动程序才能获得17,18,19,20,21,27,28,29和30的线程优先级。
5.用户模式下运行的应用程序可以获得的线程优先级如下表所示:
"相对线程优先级"向下,"进程优先级类"向右 | Idle | Below Normal | Normal | Above Normal | High | Realtime |
---|---|---|---|---|---|---|
Time-Critical | 15 | 15 | 15 | 15 | 15 | 31 |
Highest | 6 | 8 | 10 | 12 | 15 | 26 |
Above Normal | 5 | 7 | 9 | 11 | 14 | 25 |
Normal | 4 | 6 | 8 | 10 | 13 | 24 |
Below Normal | 3 | 5 | 7 | 9 | 12 | 23 |
Lowest | 2 | 4 | 6 | 8 | 11 | 22 |
Idle | 1 | 1 | 1 | 1 | 1 | 16 |
前台/后台线程:如下所示:
1.一个进程的所有前台线程都停止运行时,CLR就会强制终止还在运行的任何后台线程。
2.应用程序主线程以及Thread显示创建的任何线程都默认为前台线程。
3.线程池线程以及本机代码创建的任何线程都被标记为后台线程。