今天复习操作系统,觉着windows的线程调度策略应该写在一起,加上一个整体的认识比较好,就来写篇博客也当做复习笔记了,有些地方可能略显零散。
Windows 实现了一个由优先级驱动,抢占式的调度系统,调度过程结合实践配额调整,调度单位是线程。Windows 在单处理机系统和多处理机系统中的线程调度是不同的。
Windows采用多优先级队列,windows为每个优先级的线程都准备了优先级队列,同一优先级各线程按时间片轮转进行调度,多处理器可以多线程并行。
Windows的没有单独的调度模块或程序,调度的代码是在内核中实现的,广泛分布在内核中那些与调度相关的事件发生的地方。这些负责调度的程序被总称为“内核的调度器”。线程调度发生在DPC/Dispatch级别。
以下这些事件发生时会触发线程调度:
- 变成就绪状态的线程。例如:一个新创建的线程,或者从等待状态释放出来的线程。
- 因其时间片结束而离开运行状态的线程,它或者结束了,或者进入等待状态。
- 线程的优先级改变了,是因为系统调用,或者是Windows自己改变了优先级。
- 正在运行的线程的处理器亲合性改变了。
Windows内部使用32个优先级别,从0-31。这些数值被分成以下几类:
- [实时优先级]16个实时级别(16-31)
- [动态优先级]15个变化的级别(1-15) (一般交互式线程优先级最高)
- 1个系统级别(0), 被保留用作0页线程(零页线程:用于对系统中空闲物理页面清零)
需要注意的是Windows这里的实时优先级只是一种windows内部的命名(windows很多的命令和理论课或unix中的命名不同),并不是通常意义上的实时。
对于具备实时优先级的线程在被其他线程抢占时,具有实时优先级线程与具有可变优先级线程的行为是不同的,下面会介绍到。在应用程序中,用户可在一定范围内升高或降低线程优先级,但要把线程的优先级提升到实时优先级,用户必须有升高线程优先级的权限,如果用户进程在实时优先级运行时间过多,可能阻塞关键系统功能的执行,阻塞系统线程的运行。
在Win32 API中,每个线程的优先级都是它所属的进程的优先级和自己相关的线程优先级二者的组合。从Win32优先级映射到Windows内部数字式的优先级如图所示:
(转载自http://www.programfan.com/blog/article.asp?id=44350)
前面提到了一个概念叫做时间配额,时间配额不是一个时间长度值,而一个称为配额单位的整数。(每次从检查调度间的运行时间,很好理解,不多解释)多说一下,时间配额的作用就是可以在不提升优先级的情况下区分不同线程的运行时间,如果提升优先级来做可能导致一些线程饥饿。
调度方式有三种:
- 主动切换
- 抢占(当线程被抢占时,它被放回到相应的优先级就绪队列的队首;对实时优先级线程被抢占后分配一个完整的是时间配额,而动态优先级线程不变,下次仅运行剩余时间配额)
- 时间配额用完(没有同优先级线程会继续分配一个新的时间配额)
windows线程有优先级提升机制(总的来说是因为能更好利用CPU资源或饥饿而提高优先级):
- I/O操作完成
- 信号量或事件等待结束
- 前台进程中的线程完成一个等待操作
- 由于窗口活动而唤醒图形用户接口线程
- 线程处于就绪状态超过一定时间,但没能进入运行状态(处理机饥饿)
以上都是对于单核情况,对于多核的情况下假如有N个处理器,则N-1个处理器上活跃的线程为最高优先级的线程N-1个,独占运行,剩下的低优先级线程会共享剩余的一个处理器。但这个原则又收到处理器关联属性的影响。如果一个线程准备执行,但是唯一可用的处理器不在它的处理器关联结合中,则该线程也只能被迫等待,执行体调度下一个可以得到的线程执行。