当一个计算机是多道程序设计系统时,会频繁的有很多进程或者线程来同时竞争 CPU 时间片。尤其是有两个或两个以上的进程/线程处于就绪状态时,这种竞争关系会频繁发生。如何从就绪队列中选择下一个执行的进程或线程是由OS中的 调度程序(scheduler)
决定的,它使用的算法叫做 调度算法(scheduling algorithm)
。
许多适用于进程调度的处理方法同样也适用于线程调度。当内核管理线程的时候,调度通常会以线程级别发生,很少或者根本不会考虑线程属于哪个进程。
调度介绍
进程行为
进程通常可分为如下两种类型:
- 计算密集型(compute-bound):具有较长的 CPU 集中使用和较小频度的 I/O 等待
- I/O密集型(compute-bound):具有较短的 CPU 使用时间和较频繁的 I/O 等待
由于CPU越来越快,现在大部分进程都是I/O密集型。
何时调度
内核运行调度程序的条件(满足一条即可)
- 一个进程从running切换到waiting
- 一个进程被终结了
实际上,调度时机和进程的生命周期密不可分。通常一个进程从ready到running、从running到done、从done到waiting等状态变化发生时就是一个调度点。比如:
- 在创建一个新进程后,需要决定是运行父进程还是子进程
- 在进程退出时如何调度
- 当进程阻塞在 I/O 、信号量或其他原因时,必须选择另外一个进程来运行
- 当 I/O 中断发生时,需要进行调度
调度算法分类
总体上,调度算法可分为两类:
- 非可抢占式
- 调度程序必须等待事件结束
- 可抢占式
- 调度程序在中断被响应后执行
- 当前的进程从running切换到ready,或一个进程从waiting切换到ready
- 当前运行的进程可以被换出
这里的抢占和非抢占不仅说的是用户程序,对内核也是一样的。
当一个用户进程执行系统调用时,如果这个系统调用在内核中不会导致该进程处于等待状态,则当系统调用正常返回时会返回到发起该系统调用的进程中继续运行,也就是说在内核中不会出现抢占现象。
如果内核在进行系统调用时,由于某种事件的产生,导致内核切换到另一个优先级更高的进程去执行,从而导致这次的系统调用返回到了另一个进程。这种情况就称为抢占式内核。
在不同的系统中,调度程序的优化也是不同的:
- 批处理:一般使用非抢占式算法或者周期性比较长的抢占式算法。这可以减少线程切换因此能够提升性能
- 交互式:使用抢占式算法,这可以避免一个进程霸占 CPU 拒绝为其他进程服务
- 实时:抢占或非抢占
调度算法的目标
- 所有系统
- 公平:保证每个进程占用相同的CPU时间片
- 策略强制执行:保证规定的策略被执行
- 平衡:保持系统的所有部分都忙碌
- 批处理系统
- 吞吐量:单位时间内完成的进程数量
- 周转时间:进程从初始化到结束(包括等待)的总时间
- CPU利用率:CPU处于忙状态的时间百分比
- 交互式系统
- 响应时间:从提交请求到产生响应所花费的总时间
- 均衡性:满足用户的期望
- 实时系统
- 满足截止时间:避免丢失数据
- 可预测性:在多媒体系统中避免品质降低
指标往往是独立的,甚至是互斥的,