CPU调度室多道程序操作系统的基础。通过在进程之间切换CPU,操作系统可以提高计算机的生产效率。接下来会展示多个不同CPU的调度算法。还要阐述为特定系统选择算法的问题。
6.1 基本概念
多道程序设计的 目标是在任何时候都有一个进程在运行,以使CPU使用了最大化。在单处理器系统中,每次允许一个进程运行;任何其他进程必须等待直到CPU空闲且能被调度为止。
多道程序设计的思想比较简单。进程被执行知道它必须等待,通常等待某个I/O请求完成。在一个简单计算机系统中,CPU就会因此空闲;所有这些等待时间就浪费了。采用了多道程序设计,试图有效地使用这一时间。多个进程可同时处于内存中。当一个进程必须等待时,操作系统会从该进程拿走CPU控制权,并将CPU交给其他进程。这种方法会继续。
调度室操作系统的基本功能。几乎所有的计算机资源在使用前都需要被调度。CPU是最为重要的计算机资源。一次,CPU调度对于操作系统设计来说非常重要。
6.1.1 CPU-I/O区间周期
CPU的成功调度依赖于进程的如下观测属性:进程执行由CPU执行和I/O等待周期完成。进程在这两个状态之间切换。进程执行从CPU区间(CPU burst)开始。在这之后是I/O区间(I/O burst),接着是另一个CPU区间,接着另一个I/O区间,如此进行下去。最终,最后的CPU区间通过系统请求终止执行,而不是又一个I/O区间(如下图)。
这些CPU区间的长度已经被大量地测量过。虽然它们随着进程和计算机的不同变换很大,但是它们都呈现出类似图6.2 所示的频率曲线。该曲线通常表征为指数或超指数形式,具有大量短CPU区间和少量长CPU区间。I/O约束程序通常具有很多段CPU区间。CPU的约束程序可能有少量的长CPU区间。这种分布能有助于人们选择合适的CPU调度算法。
6.1.2 CPU调度程序
每当CPU变为空闲时,操作系统就必须从就绪队列中选择一个进程执行。进程选择由短期调度程序(short-term shcedular, 或CPU调度程序)执行。调度程序从内存中就绪可执行的进程里选择一个,并为其中之一分配CPU。
就绪队列不必是先进先出(FIFO)队列。正如研究各种调度算法时将看到的,就绪队列可实现为FIFO队列、优先队列、树或仅仅是无序链表。不过,从概念上来说,就绪队列内的所有进程都要哦排队等待机会再CPU上运行。队列中的记录通常是进程的进程控制块(process control block ,PCB)。
6.1.3 可抢占式调用
CPU调度决策可在如下四种环境下发生:
- 当进程从运行状态切换到等待状态(例如,I/O请求或调用wait 以等待一个子进程的终止)。
- 当一个进程以运行状态切换到就绪状态(例如,当出现中断时)。
- 当一个进程从等待状态切换到就绪状态(例如,I/O完成)。
- 当一个进程终止时。
对于第一和第四两种情况,就调度而言没有选择。一个新进程(如果就绪队列有一个进程存在)必须被选择执行。不过,对于第二和第三两种情况,可以进程选择。
当调度只能发生在第一和第四两种情况时, 称调度方案是 非抢占(nonpreemptive)的;否则,调度方案是可抢占(preemptive)的。采用非抢占调度,一旦CPU被分配给一个进程,那么该进程会一直使用CPU知道进程终止或切换到等待状态是释放 CPU。以前的 Windowds3.1 和 Apple Macintosh 操作系统都使用这种调度方法。在有的硬件平台上。这是唯一可以使用的方法,因为它不要求特别的硬件(如定时器)来支持可抢占式调度。
可是,抢占式调度是有代价的。考虑两进程共享数据的情况。第一个进程被抢占时可能正在更新数据,而第二个进程开始运行。第二个进程可能试图读数据,该数据现在处于不一致状态。因此需要有新机制以用来协调对共享数据的访问;第一问题将在接下来讨论。
抢占对于操作系统内核的设计也有影响。在处理系统调用时,内核可能 忙于为进程而 活动。这些活动可能涉及改变重要内核数据(例如,I/O队列)。如果一个进程在进行这些修改且内核(或设备驱动程序)需要读或修改同一结构时被抢占,那么会有什么结果呢? 肯定会导致 混乱。有的操作系统如绝大多数UNIX系统,通过在上下文切换之前等待系统调用完成或等待发生I/O阻塞来处理这一问题。这种方法确保内核结构简单,因为在内核数据结构处于不一致状态时,内核不会抢占一个进程。遗憾的是,这种内核执行模型对实时计算和多处理器的支持较差。这些问题及其解决方案在接下来讨论。
对UNIX的情况来说,代码段仍处于危险。因为根据定义中断可以随时发生,而且不能总是被内核所忽略,所以受中断影响的代码段必须加以保护比避免同时使用。操作系统需要在几乎所有时候能接受中断,否则输入会被丢失或输出会被改写。为了这些代码段不被多个进程同时访问,所以在进入时要禁止中断而在退出时要重新允许中断。可遗憾的是,禁止中断和允许中断很花费时间,尤其是对于多处理系统。为了让系统可有效地利用多个CPU, 必须尽量减少中断状态的改变而尽量增加锁的细化程序。
6.1.4 分派程序
与CPU调度功能有关的另一部分是分配程序。分配程序是一个模块,用来将CPU的控制交给由短期调度程序所选择的进程。其功能包括:
- 切换上下文
- 切换到用户模式
- 跳转到用户程序的合适位置以重启这个程序。
分配程序应尽可能快,因为在每次进程切换时都要使用。分配程序停止一个进程而启动另一个进程执行所要花费的时间成为分派延迟(dispatch latency)。