2.1 线程调度基本概念
抢占式操作系统
- 对于现在大部分的 OS 而言,抢占式的操作系统必须使用算法来判断,在什么时候调度哪些线程,调度多少时间,并为其分配时间片;
- 线程调度
- 在一个时间片 (time-slice) 之后,Windows 检查现存的所有线程的内核对象;
- 在这些对象中,只有那些没有正在等待什么的线程才适合调度;
- Windows 选择一个可调度的线程内核对象,并上下文切换到它
- 抢占式
- 线程可以在任何时间停止,即被抢占,然后切换并调度到另一个线程;
2.2 优先级
线程与优先级
- 每个线程都分配了从 0 (最低) 到 31 (最高) 的优先级;
- 调度策略
- 核心:较高优先级的线程总是抢占低优先级的线程;
- 优先调度方法
- 系统决定为 CPU 分配线程执行时,首先检查优先级 31 的线程,并以一种轮流的方式调度它们;
- 如果优先级 31 的一个线程可以调度,就把它分配给 CPU;
- 在这个线程的时间片结束时,系统检查是否有另一个优先级 31 的线程可以运行。如果是,就允许将那个线程分配给 CPU;
- 饥饿
- 只要存在可调度的优先级 31 的线程,系统就永远不会将优先级 0~30 的任何线程分配给 CPU;
- 较高优先级的线程占用了太多 CPU 时间,造成较低优先级的线程无法运行;
- 多处理器机器发生饥饿的可能性要小得多,因为这种机器上优先级为 31 的线程和优先级为 30 的线程可以同时运行。
- 系统总是保持各个 CPU 处于忙碌状态,只有没有线程可调度的时候,CPU 才会空闲下来;
2.2.1 优先级类与优先级
Windowx 如何确定进程优先级
- 为了能够确定线程使用什么具体的优先级数值,需要为进程选择一个优先级类;
进程优先级
- 进程优先级
- 用于管理引用进程之间的关系;
- 一个有六种进程优先级类,默认的 Normal 是最常用的优先级类;
- 支持 6 个进程优先级类
- Idle
- 在系统中什么事情都不做的时候,可以分配为 Idle 优先级;
- BelowNormal
- Normal
- AboveNormal
- High
- 只有绝对必要的时候才应使用 High 优先级类;
- Realtime
- Realtime 优先级类要尽可能地避免,Realtime 优先级相当高,甚至可能干扰操作系统任务,比如阻碍一些必要的磁盘 I/0 和网络传输;
- Idle
线程优先级
- 什么是相对线程优先级
- 线程的优先级相对于进程;
- 进程是一个进程优先级类的成员,在进程中,要为各个线程分配相对的优先级;
- 线程的优先级是由线程的优先级以及所处进程的优先级一起决定的;
- 相对线程优先级级别
- Windows 支持七种相对线程优先级
- ldle,Lowest,Below Normal,Normal,AboveNormal,Highest 和 Time-Critical;
- 进程优先级到线程优先级映射
- 映射线程的具体优先级数值;
2.2.2 一些调度的策略
优先降低线程优先级
- 最好是降低一个线程的优先级,而不是提升另一个线程的优先级;
- 如果线程要执行长时间的计算限制任务,比如编译代码、拼写检查、电子表格重新计算等,一般应降低该线程的优先级;
- 如果线程要快速响应某个事件,运行短暂时间,再恢复为等待状态,则应提高该线程的优先级;
关于高优先级
- 高优先级线程在其生存期的大多数时间里,都应处于等待状态。这样才不至于影响系统的总体响应能力;
2.3 前台线程与后台线程
CLR 与前后台线程
- CLR 中的线程全部都是前台线程或者后台线程中的一种;
- 一个进程的所有前台线程停止运行时,CLR 会强制终止任何正在运行的后台线程;
前后台线程使用范围
- 前台线程
- 使用前台线程执行确实想完成的事情;
- 使用 Thread 对象显示创建的任何线程,默认为前台线程;
- 尽量少使用前台线程;
- 后台线程
- 非关键性任务使用后台线程;
- 线程池默认为后台线程;
- 由进入托管环境执行的本机代码创建的任何线程,都被标记为后台线程;