Process Scheduling
[! danger] CPU 调度 $\neq$ 进程调度
见CPU-Scheduling, 进程调度只是一个层级的 CPU 调度。
进程调度
进程调度是调度器从就绪队列中选出下一个运行实体。它只完成“选谁”,并没有完成现场切换,也没有直接返回用户态。
一次完整的控制权交接依次经过:
- 中断、异常或系统调用使 CPU 进入内核态。
- 调度器从就绪队列中选出下一个运行实体。(即进程调度)
- 分派器保存原现场,恢复新现场。
- 内核执行中断或陷入返回,才进入被选中进程的用户态代码。
调度决策完成时仍在内核态。真正回到用户态的分界点,是分派完成后执行中断返回或陷入返回指令。
发生进程调度的时机
运行进程下处理机时,必须另选一个进程;新进程创建或被唤醒的进程进入就绪态时,是否发生调度取决于调度方式和优先级。
| 发生的事件 | 调度结果 |
|---|---|
| 正常退出或异常终止 | 必须选择其他就绪进程 |
| 请求 I/O、等待资源或事件而阻塞 | 必须选择其他就绪进程 |
| 时间片用完 | 抢占式系统通常把它放回就绪队列并重新选择 |
| 新进程创建完成,进入就绪态 | 抢占式系统可能立即改选更合适的进程 |
| 阻塞进程被唤醒,进入就绪态 | 抢占式系统可能立即改选更高优先级进程 |
| 中断或系统调用处理即将结束 | 内核在返回前检查是否需要重新调度。若被唤醒者优先级更高,抢占式调度才可能让当前进程让出 CPU。 |
不能立刻切换的情况
内核可以先记录需要调度,等到能够安全切换的位置再执行分派。
| 情况 | 为什么暂缓切换 |
|---|---|
| 中断处理尚未完成 | 要先保存或恢复必要的硬件和内核状态 |
| 正在修改调度队列等内核关键结构 | 中途切换可能让其他代码看到不一致数据 |
| 正在执行不可分割的内核操作 | 必须先完成原子更新 |
进程处于普通临界区时,不一定禁止处理机调度。比如进程正在使用打印机,打印机是慢速设备,如果一直不允许调度,CPU 可能长期空闲。
不能调度的是操作系统内核程序临界区。这类临界区访问的是内核管理数据,例如就绪队列、阻塞队列、PCB 链表。若这些结构还没维护完就切换,会让后续调度、唤醒、阻塞等操作读到不一致状态。
中断处理程序可以发现需要调度,但完整的进程切换通常要等到中断处理结束后的安全位置再执行。
调度方式
进程调度方式按是否允许强行收回 CPU,可分为非抢占式和抢占式。
| 调度方式 | 也称 | 规则 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
| 非抢占式调度 | 非剥夺调度 | 只允许进程主动放弃 CPU | 实现简单,系统开销小 | 不能及时处理紧急任务 | 早期批处理系统 |
| 抢占式调度 | 剥夺调度 | 更重要或更紧急的进程到达时,可以暂停当前进程 | 响应快,可实现时间片轮转和实时响应 | 切换开销更大,需要更复杂的保护机制 | 分时系统、实时系统 |
非抢占式系统中,运行进程阻塞或退出时才触发调度。抢占式系统中,每个时钟中断或若干个时钟中断都可能触发调度程序工作。
[! danger] 系统调用结束后不一定立即返回发起进程
发起系统调用的进程进入内核后,可能因为等待 I/O 而阻塞,也可能在系统调用完成时遇到更高优先级进程就绪。抢占式调度器可以选中其他进程,把原进程放入就绪队列。原进程以后再次获得 CPU 时,才从系统调用返回到自己的用户态代码。
分派器
调度器和分派器不是同一件事。
调度器 scheduler 负责做选择:
- 让谁运行。
- 按什么调度算法选择。
- 在时间片轮转等策略中,运行多长时间。
分派器 dispatcher 负责把 CPU 真正交给被选中的进程:
- 保存当前进程的处理机现场。
- 恢复新进程的处理机现场。
- 切换到新进程的地址空间和内核栈等运行环境。
- 让 CPU 从新进程上次停下的位置继续执行。
可以这样区分:
- 狭义的进程调度:只指从就绪队列中选中一个进程。
- 进程切换:一个进程让出 CPU,由另一个进程占用 CPU。
- 广义的进程调度:选择进程 + 进程切换。
进程切换过程
进程切换主要完成两类动作:
- 保存原来运行进程的各种数据。
- 恢复新进程的各种数据。
这些数据包括程序计数器 PC、程序状态字 PSW、通用寄存器、栈指针等处理机现场信息。它们通常保存在 PCB 中。
一次典型切换可以按以下顺序理解:
- 当前进程因为时间片用完、阻塞、终止或被抢占而离开运行态。
- 内核保存当前进程的 CPU 现场到该进程 PCB。
- 内核修改当前进程状态,并把 PCB 放入合适队列。
- 调度器从就绪队列选择下一个进程。
- 分派器从新进程 PCB 恢复 CPU 现场。
- 新进程进入运行态,从保存的 PC 位置继续执行。
进程切换有代价。调度和切换过于频繁时,系统会把大量时间花在保存、恢复现场和维护队列上,真正用于执行用户进程的时间反而减少。
闲逛进程
当没有其他就绪进程时,调度程序会选择闲逛进程,即 idle process。
闲逛进程的特点:
- 优先级最低。
- 只有没有其他就绪进程时才运行。
- 可以设计为能耗较低的循环或特殊指令序列。
- 它占用 CPU 的目的不是完成用户任务,而是让 CPU 在无事可做时保持一个可控状态,并在指令周期末尾继续检查中断。
闲逛进程的存在说明:CPU 在操作系统管理下通常总运行着一个进程。没有用户进程可运行时,就是 idle。