目录:算法
26.1 Windows为何要支持线程缓存
26.2 线程开销服务器
26.3 中止疯狂数据结构
26.4 CPU发展趋势架构
26.5 CLR线程和Windows线程并发
26.6 使用专用线程执行异步的计算限制操做异步
26.7 使用线程的理由函数
26.8 线程调度和优先级性能
26.9 前台线程和后台线程学习
26.10 继续学习
做为一个Windows概念,线程的职责是对CPU进行虚拟化。Windows为每一个进程都提供了改进程专用的线程(功能至关于一个CPU)。应用程序的代码进入死循环,与那个代码关联的进程回“冻结”,但其余进程不会冻结,会继续执行。
线程容许用户强制终止彷佛已冻结的应用程序。和一切虚拟化机制同样,线程有空间(内存耗用)和时间(运行时的执行性能)上的开销。
线程内核对象:OS为系统中建立的每一个线程都分配并初始化这种数据结构之一。数据结构包含一组对线程进行描述的属性。数据结构还包含所谓的线程上下文。上下文是包含CPU寄存器集合的内存块。
线程环境块(TEB):TEB是在用户模式(应用程序代码能快速访问的地址空间)中分配和初始化的内存块。TEB耗用1个内存页。TEB包含线程的异常处理链首。线程进入的每一个try块都在链首插入一个节点;线程退出try块时从链中删除改节点。TEB还包含线程的“线程本地存储”数据,以及由GDI和OpenGL图形使用的一些数据结构。
用户模式栈:用户模式栈存储传给方法的局部变量和实参。它包含一个地址;指出当前方法返回时,线程应该从什么地方接着执行。
内核模式栈:应用程序代码向操做系统中的内核模式函数传递实参时,还会使用内核模式栈。
DLL线程链接(attach)和线程分离(detach)通知:Windwos的一个策略是,任什么时候候在进程中建立线程,都会第哦啊用进程中加载的全部非托管DLL的DllMain方法,并向该方法传递DLL_THREAD_ATTACH标志。任何线程终止,都会调用进程中的全部非托管DLL的DllMain方方法,并向方法传递DLL_THREAD_DETACH标志。
Windows任什么时候刻只将一个线程分配给一个CPU。那个线程能运行一个“时间片(也称为“量”或“量程”)”的长度。时间片到期,Windows就上下文切换到另外一个线程:
1.将CPU寄存器的值保存到当前正在运行的线程的内核对象内部的一个上下文结构中。
2.从现有线程集合中选出一个线程供调度。若是该线程由另外一个进程拥有,Windows在开始执行任何代码或者接触任何数据以前,还必须切换CPU“看见”的虚拟地址空间。
3.将所选上下文结构中的值加载到CPU的寄存器中。
上下文切换时净开销;所产生的开销不会换来任何内存或性能上的收益。因此说上下文切换时经过牺牲性能来换取更好的用户体验。
执行上下文切换所需的时间取决于CPU架构和速度。而填充CPU缓存所须要的时间取决于系统中运行的应用程序,CPU缓存的大小以及其余各类因素。
执行垃圾回收时,CLR必须挂起(暂停)全部线程,遍历它们的栈来查找根以便对堆中的对象进行标记,再次遍历它们的栈,在恢复全部线程。
多个CPU
超线程芯片
多核芯片
CLR使用Windows的线程处理功能,CLR线程彻底等价于Windows线程。
知足如下条件就能够建立本身的线程:
线程须要以非普通线程优先级运行。
须要线程表现为要给前台线程,防止应用程序在线程结束任务前终止。
计算限制的任务须要长时间运行。
要启动线程,并可能调用Thread的Abort方法来提早终止它。
可响应性(一般是对于客户端GUI应用程序)
Windows为每一个进程提供它本身的线程,确保发生死循环的应用程序不会妨碍其余应用程序。
性能(对于客户端和服务器应用程序)
因为Windows每一个CPU调度一个线程,并且多个CPU能并发执行这些线程,因此同时执行多个操做能提高性能。
抢占式操做系统必须使用算法判断在何时调度哪些线程多长时间——线程可在任什么时候间中止(被抢占)并调度另外一个线程。(每一个线程的内核对象包含一个上下文结构,上下文结构反映了线程上一次执行完毕后CPU寄存器的状态。在一个时间片以后,Windows检查现存的全部线程内核对象。在这些对象中,只有那些没有正在等待什么的线程才适合调度。Windows选择一个可调度的线程内核对象,并上下文切换到它。Windows实际记录了每一个线程被上下文切换到的次数。而后,线程开始执行代码,并在其进程的地址空间处理数据。又过过了一个时间片以后,Windows执行下一次上下文切换。Windows从系统启动开始便一直执行上下文切换,直到系统关闭为止。)
每一个线程都分配了从0到31的优先级。饥饿:较高优先级的线程占用了太多CPU时间,形成较低优先级的线程没法运行。
系统启动时会建立一个特殊的零页线程,该线程的优先级是0,并且是整个系统惟一优先级为0的线程。在没有其余线程须要“干活儿”的时候,零页线程将系统RAM的全部空闲页清零。
进程优先级类:Idle,Below Normal,Above Normal,High,Realtime.
相对线程优先级:Idle,Lowest,Below Normal,Normal,Above Normal,Highest,Time-Critical.
相对线程优先级 | 进程优先级类 | |||||
Idle | Below Normal | Normal | Above Nomal | 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 | 3 | 8 | 11 | 22 |
Idle | 1 | 1 | 1 | 1 | 1 | 16 |
CLR将每一个线程要么视为前台线程,要么视为后台线程。一个进程的全部前台线程中止运行时,CLR强制终止仍在运行的任何后台线程。这些后台线程被直接终止,不抛出异常。
应用程序的主线程以及经过构造一个Thread对象来显式建立的任何线程都默认为前台线程,线程池线程默认为后台线程。由进入托管执行环境的本机代码建立的任何线程被标记为后台线程