> For the complete documentation index, see [llms.txt](https://lfool.gitbook.io/operating-system/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lfool.gitbook.io/operating-system/di-er-zhang-jin-cheng-guan-li/6.-jin-cheng-de-tiao-du.md).

# 6. 进程的调度

&#x20;[知识脑图](https://lfool.github.io/os_mind/process_scheduling.html)

## 1. 调度的概念

当有一堆任务需要处理的时候，但由于资源有限，这些事情没发同时处理。这就需要确定某种规则来决定处理这些任务的顺序，这就是“调度”研究的问题

## 2. 调度的三个层次

### 2.1 高级调度

先明确一个概念：

* **作业：**&#x4E00;个具体的任务
* 用户向系统提交一个作业 ≈ 用户让操作系统启动一个程序（来处理一个具体的任务）

**高级调度（作业调度）：**&#x6309;一定的原则从外存的作业后备队列中选择一个作业调入内存，并创建进程。**每个作业只调入一次，调出一次**。作业调入时会建立 PCB，调出时才撤销 PCB&#x20;

> 好几个程序需要启动，到底先启动哪个

### 2.2 中级调度

当内存不够时，可能会把某些进程的数据调出到外存。等内存空闲时或者进程需要运行时再重新调入内存中

暂时调到外存等待的进程状态为**挂起状态**。被挂起的进程 PCB 会被组织成挂起队列

**中级调度（内存调度）：**&#x6309;照某种策略决定将哪个处于挂起的进程重新调入内存。一个进程可能多次调出、调入内存，因此**中级调度**发生的**频率**要比高级调度**高**

#### 补充知识：进程的挂起态 & 七状态模型

暂时调到外存等待的进程状态为**挂起状态（挂起态，suspend）**

挂起态可以分为**就绪挂起**、**阻塞挂起**两种

![](/files/-MF0MWUTBxi7IiFo74bG)

**挂起 & 阻塞 区别**

两种都是不能获得 CPU 的服务，但是挂起态是将进程从内存调出到外存中，而阻塞态的进程依然在内存中

有的操作系统会把就绪挂起和阻塞挂起分为两个队列，甚至可以根据阻塞的原因将阻塞队列细分为更多的队列

### 2.3 低级调度

低级调度（进程调度 / 处理机调度）：按照某种策略从就绪队列中选取一个进程，将处理机分配给它（内存 -> CPU）

进程调度是操作系统中最基本的一种调度，在一般的操作系统中都必须配置进程调度。进程调度的频率很高，一般几十毫秒一次。

### 2.4 三种调度的联系 & 对比

|                          |                      **要做什么**                      |  **调度发生在...**  | **发生频率** |       **对进程状态的影响**      |
| :----------------------: | :------------------------------------------------: | :------------: | :------: | :---------------------: |
|  <p>高级调</p><p>（作业调度）</p> | <p>按照某种规则，从后备队列中</p><p>选择合适的的作业将其调入内存中，并为其创建进程</p> | 外存 -> 内存（面向作业） |    最低    |     无 -> 创建态 -> 就绪态     |
| <p>中级调度</p><p>（内存调度）</p> |     <p>按照某种规则，从挂起队列中</p><p>选择合适的的进程将其数据调回内存</p>    | 外存 -> 内存（面向进程） |    中等    | 挂起态 -> 就绪态（阻塞挂起 -> 阻塞态） |
|        低级调度（进程调度）        |      <p>按照某种规则，从就绪队列中</p><p>选择一个进程为其分配处理机</p>      |    内存 -> CPU   |    最高    |        就绪态 -> 运行态       |

## 3. 进程调度的时机

**需要进行**进程调度与切换的情况

* 当前运行的进程**主动放弃**处理机
  * 进程正常终止
  * 运行过程中发生异常而终止
  * 进程主动请求阻塞（如：等待 I/O）
* 当前运行的进程**被动放弃**处理机
  * 分给进程的时间片用完
  * 有更紧急的事情需要处理（如：I/O 中断）
  * 有更高优先级的进程进入就绪队列

**不能进行**进程调度与切换的请况

* 在**处理机中断的过程中**。中断处理过程复杂，与硬件密切相关，很难做到在中断处理中进行进程切换
* 进程在**操作系统内核程序临界区**中
* 在**原子操作过程中**（原语）。原子操作不可中断，要一起呵成

## 4. 进程调度的方式

**非剥夺调度方式**，又称**非抢占方式**。即，只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达，当前进程依然会继续使用处理机，直到该进程终止或主动要求进入阻塞态

* 实现简单，系统开销小但是无法及时处理紧急任务，适合于早期的批处理系统

**剥夺调度方式**，又称**抢占方式**。当一个进程正在处理机上执行时，如果有一个更重要或更紧急的进程需要使用处理机，则立即暂停正在执行的进程，将处理机分配给更重要紧迫的进程

* 可以优先处理更紧急的进程，也可以实现让各进程按时间片轮询执行的功能（通过时钟中断）。适合于分时系统、实时系统

## 5. 进程的切换 & 过程

“狭义的进程调度”与“进程切换”的区别：&#x20;

* **狭义的进程调度**指的是从就绪队列中**选中一个要运行的进程**。（这个进程可以是刚刚被暂停执行的进程，也可能是**另一个进程**，后一种情况就需要**进程切换**）
* **进程切换**是指一个进程让出处理机，由另一个进程占用处理机的过程

**广义的进程调度**包含了**选择一个进程**和**进程切换**两个步骤

**进程切换的过程**主要完成了：

1. 对原来运行进程各种数据的保存
2. 对新的进程各种数据的恢复（如：程序计数器、程序状态字、各种数据寄存器等处理机现场信息，这些信息一般保存在进程控制块）

**注意：进程切换是有代价的**，因此如果**过于频繁**的进行进程**调度**、**切换**，必然会使整个**系统的效率降低**，使系统大部分时间都花在了进程切换上，而真正用于执行进程的时间减少

## 6. 调度算法的评价指标

### 6.1 CPU 利用率

**CPU 利用率：**&#x6307; CPU “忙碌” 的时间占总时间的比例

$$\begin{aligned} 利用率 = \frac{忙碌的时间}{总时间} \qquad\end{aligned}$$&#x20;

### 6.2 系统吞吐量

**系统吞吐量：**&#x5355;位时间内完成作业的数量

$$\begin{aligned} 系统吞吐量 = \frac{总共完成了多少道作业}{总共花了多少时间} \qquad\end{aligned}$$&#x20;

### 6.3 周转时间

对于计算机的用户来说，他很关心**自己的作业从提交到完成花了多少时间**

**周转时间：**&#x6307;**从作业被提交给系统开始**，到**作业完成为止**的这段时间间隔

周转时间包括四个部分：作业在外存后备队列上等待作业调度（高级调度）的时间、进程在就绪队列上等 待进程调度（低级调度）的时间、进程在CPU上执行的时间、进程等待I/O操作完成的时间。后三项在一个作业的整个处理过程中，可能发生多次

$$（作业）周转时间= 作业完成时间– 作业提交时间$$&#x20;

$$\begin{aligned} 平均周转时间 = \frac{各作业周转时间之和}{作业数} \qquad \end{aligned}$$&#x20;

$$\begin{aligned} 带权周转时间 =  \frac{作业周转时间}{作业实际运行的时间} \qquad   =  \frac{作业完成时间 - 作业提交时间}{作业实际运行的时间} \qquad \end{aligned}$$&#x20;

$$\begin{aligned} 平均带权周转时间 = \frac{各作业带权周转时间之和}{作业数} \qquad \end{aligned}$$&#x20;

### 6.4 等待时间

计算机的用户希望**自己的作业尽可能少的等待处理机**

**等待时间：**&#x6307;进程 / 作业**处于等待处理机状态时间之和**，等待时间越长，用户满意度越低

对于**进程**来说，等待时间就是指进程建立后**等待被服务的时间之和**，在等待 I/O 完成的期间其实进程也是在被服务的，所以不计入等待时间

对于**作业**来说，不仅要考虑**建立进程后的等待时间，还要加上作业在外存后备队列中等待的时间**

一个作业总共需要被 CPU 服务多久，被 I/O 设备服务多久一般是确定不变的，因此调度算法其实只会影响作业/进程的等待时间。当然，与前面指标类似，也有“**平均等待时间**”来评价整体性能

### 6.5 响应时间

对于计算机用户来说，会希望自己的提交的请求（比如通过键盘输入了一个调试命令）尽早地开始被系统服务、回应

**响应时间：**&#x6307;从用户**提交请求**到**首次产生响应**所用的时间

## 7. 调度算法

各种调度算法研究思路：

1. 算法思想
2. 算法规则
3. 这种调度算法是用于 作业调度 还是 进程调度
4. 抢占式？非抢占式？
5. 优点 & 缺点
6. 是否会导致**饥饿**（某进程 / 作业长期得不到服务）

**无交互**

|    算法   |                            可抢占？                            |                    优点                    |                    缺点                   | <p>考虑到等待时间</p><p>&</p><p>运行时间？</p> | 会导致饥饿？ |
| :-----: | :--------------------------------------------------------: | :--------------------------------------: | :-------------------------------------: | :--------------------------------: | :----: |
|   FCFS  |                            非抢占式                            |           <p>公平</p><p>实现简单</p>           |                  对短作业不利                 |     <p>等待时间 √</p><p>运行时间 ×</p>     |   不会   |
| SJF/SPF | <p>默认为非抢占式；</p><p>也有 SJF 的抢占式版本</p><p>最短剩余时间有限算法（SRTN）</p> | <p>最短的</p><p>平均等待</p><p>/</p><p>周转时间</p> | <p>对长作业不利，可能导致饥饿</p><p>难以做到真正的短作业优先</p> |     <p>等待时间 ×</p><p>运行时间 √</p>     |    会   |
|   HRRN  |                            非抢占式                            |                                          |                                         |     <p>等待时间 √</p><p>运行时间 √</p>     |   不会   |

**有交互**

|   算法   |            可抢占？           |             优点             |               缺点               | 会导致饥饿？ |                         补充                         |
| :----: | :-----------------------: | :------------------------: | :----------------------------: | :----: | :------------------------------------------------: |
|  时间片轮转 |            抢占式            |   <p>公平</p><p>适用于分时系统</p>  |   <p>频繁切换有开销</p><p>不区分优先级</p>  |   不会   |             <p>时间片太大</p><p>或太小有何影响？</p>            |
|  优先级调度 | <p>既有抢占式</p><p>也有非抢占式</p> | <p>区分优先级</p><p>适用于实时系统</p> |             可能导致饥饿             |    会   | <p>动态/静态优先级</p><p>各类型进程如何设置优先级？</p><p>如何调整优先级？</p> |
| 多级反馈队列 |            抢占式            |          平衡系统（优秀）          | <p>一般不说它有缺点</p><p>不过可能导致饥饿</p> |    会   |                                                    |

## 8. 先来先服务（FCFS）

* **算法思想：**&#x4E3B;要从 “公平” 的角度考虑（类似生活中排队买东西）
* **算法规则：**&#x6309;照作业 / 进程达到的先后顺序进行调度，等待时间越久的就越优先得到服务
* **用于作业 / 进程调度：**&#x7528;于作业调度时，考虑的是哪个作业先到达后备队列；用于进程调度时，考虑的是哪个进程先到达就绪队列
* **是否可抢占：**&#x975E;抢占式的算法
* **优缺点：**
  * **优点：**&#x516C;平、算法实现简单
  * **缺点：**&#x6392;在长作业（进程）后面的短作业需要等待很长时间，带权周转时间很大，对短作业来说用户体验不好。即， FCFS 算法对长作业有利，对短作业不利（Eg ：排队买奶茶…）
* **是否会导致饥饿：**&#x4E0D;会

### 例子

![](/files/-MF12si5AsA9BqmKWlOQ)

## 9. 短作业优先（SJF）

* **算法思想：**&#x8FFD;求最少的平均等待时间，最少的平均周转时间、最少的平均平均带权周转时间
* **算法规则：**&#x6700;短的作业 / 进程优先得到服务（所谓“最短”，是指要求服务时间最短）
* **用于作业 / 进程调度：**&#x5373;可用于作业调度，也可用于进程调度。用于进程调度时 称为“短进程优先（SPF, Shortest Process First）算法”
* **是否可抢占：**&#x53;JF和SPF是**非抢占式**的算法。但是**也有抢占式的版本**——**最短剩余时间优先**算法（SRTN, Shortest Remaining Time Next）
* **优缺点：**
  * **优点：**“最短的”平均等待时间、平均周转时间
  * **缺点：**&#x4E0D;公平。对短作业有利，对长作业不利。可能产生 饥饿现象。另外，作业/进程的运行时间是由用户提供的，并不一定真实，不一定能做到真正的短作业优先
* **是否会导致饥饿：**&#x4F1A;。如果源源不断地有短作业/进程到来，可能使长作业/进程长时间得不到服务，产生“饥饿”现象。如果一直得不到服务，则称为“饿死”

### 细节

1. 如果未特别说明，所提到的“短作业/进程优先算法”**默认**是**非抢占式**的
2. 很多书上都会说“SJF 调度算法的平均等待时间、平均周转时间最少”
   * 严格来说，这个表述是错误的，不严谨的。之前的例子表明，最短剩余时间优先算法得到的平均等待时间、平均周转时间还要更少
   * 应该加上一个条件“**在所有进程同时可运行**时，采用SJF调度算法的平均等待时间、平均周转时间最少”
   * 或者说“在**所有进程都几乎同时到达**时，采用SJF调度算法的平均等待时间、平均周转时间最少”
   * 如果不加上述前提条件，则应该说“**抢占式的**短作业/进程优先调度算法（**最短剩余时间优先**, **SRNT**算法）的平均等待时间、平均周转时间最少”
3. 虽然严格来说，SJF的平均等待时间、平均周转时间并不一定最少，但相比于其他算法（如FCFS）， SJF依然可以获得较少的平均等待时间、平均周转时间
4. 如果选择题中遇到“SJF 算法的平均等待时间、平均周转时间最少”的选项，那最好判断其他选项是不是有很明显的错误，如果没有更合适的选项，那也应该选择该选项

### 例子（SJF）

**短作业/进程优先调度算法：**&#x6BCF;次调度时选择**当前已到达**且**运行时间最短**的作业/进程

![](/files/-MF15Ko88a6qk8o98jqq)

### 例子（SRTN）

**最短剩余时间优先算法：**&#x6BCF;当有进程加入**就绪队列改变时就需要调度**，如果新到达的进程**剩余时间**比当前运行的进程剩余时间**更短**，则由新进程**抢占**处理机，当前运行进程重新回到就绪队列。另外，当**一个进程完成时也需要调度**

![](/files/-MF16OSXeX-ShtwIq-Jm)

## 10. 高响应比优先（HRRN）

* **算法思想：**&#x8981;综合考虑作业/进程的等待时间和要求服务的时间
* **算法规则：**&#x5728;每次调度时先计算各个作业/进程的响应比，选择响应比最高的作业/进程为其服务

  * $$\begin{aligned} 响应比 = \frac{等待时间 + 要求服务时间}{要求服务时间} \qquad \end{aligned}$$&#x20;
* **用于作业 / 进程调度：**&#x65E2;可用于作业调度，也可用于进程调度
* **是否可抢占：**&#x975E;抢占式的算法。因此只有当前运行的作业/进程主动放弃处理机时，才需要调度，才需要计算响应比
* **优缺点：**
  * 综合考虑了等待时间和运行时间（要求服务时间）
  * 等待时间相同时，要求服务时间短的优先（SJF 的优点）
  * 要求服务时间相同时，等待时间长的优先（FCFS 的优点）
  * 对于长作业来说，随着等待时间越来越久，其响应比也会越来越大，从而避免了长作业饥饿的问题
* **是否会导致饥饿：** 不会

### 例子

**高响应比优先算法：非抢占式**的调度算法，只有当前运行的进程**主动放弃CPU时**（正常/异常完成，或主动阻塞），才需要进行调度，调度时**计算所有就绪进程的响应比**，**选响应比最高的**进程上处理机

![](/files/-MF18qE3_IlXEZEOSv7d)

## 11. 时间片轮转调度算法（RR）

* **算法思想：**&#x516C;平地、轮流地为各个进程服务，让每个进程在一定时间间隔内都可以得到响应
* **算法规则：**&#x6309;照各进程到达就绪队列的顺序，轮流让各个进程执行一 个**时间片**（如 100 ms）。若进程未在一个时间片内执行完，则剥夺处理机，将进程重新放到就绪队列队尾重新排队
* **用于作业 / 进程调度：**&#x53EA;用于进程调度（只有作业放入内存建立了相应的进程后，才能被分配处理机时间片）
* **是否可抢占：**&#x82E5;进程未能在时间片内运行完，将被强行剥夺处理机使用权，因此时间片轮转调度算法属于**抢占式**的算法。由时钟装置发出**时钟中断**来通知 CPU 时间片已到
* **优缺点：**
  * **优点：**&#x516C;平；响应快，适用于分时操作系统
  * **缺点：**&#x7531;于高频率的进程切换，因此有一定开销；不区分任务的紧急程度
* **是否会导致饥饿：** 不会

### 时间片太大或太小分别有什么影响？

如果**时间片太大**，使得每个进程都可以在一个时间片内就完成，则时间片轮转调度算法**退化为先来先服务**调度算法，并且会增大进程响应时间。因此时间片不能太大。

另一方面，进程调度、切换是有时间代价的（保存、恢复运行环境），因此如果**时间片太小**，会导致**进程切换过于频繁**，系统会花大量的时间来处理进程切换，从而导致实际用于进程执行的时间比例减少。可见**时间片也不能太小**

### 例子

![](/files/-MF1Bld69-jItSzgBC7P)

## 12. 优先级调度算法

* **算法思想：**&#x968F;着计算机的发展，特别是实时操作系统的出现，越来越多的应用场景需要根据任务的紧急程度来决定处理顺序
* **算法规则：**&#x6BCF;个作业/进程有各自的优先级，调度时选择优先级最高的作业/进程
* **用于作业 / 进程调度：**&#x65E2;可用于作业调度，也可用于进程调度。甚至，还会用于在之后会学习的 I/O 调度中
* **是否可抢占：**&#x62A2;占式、非抢占式都有。区别在于：非抢占式只需在进程主动放弃处理机时进行调度即可，而抢占式还需在就绪队列变化时，检查是否会发生抢占
* **优缺点：**
  * **优点：**&#x7528;优先级区分紧急程度、重要程度，适用于实时操作系统。可灵活地调整对各种作业/进程的偏好程度
  * **缺点：**&#x82E5;源源不断地有高优先级进程到来，则可能导致饥饿
* **是否会导致饥饿：** 会

### 重点：

根据优先级是否可以动态改变，可将优先级分为**静态优先级**和**动态优先级**两种

* **静态优先级：**&#x521B;建进程时确定，之后一直不变
* **动态优先级：**&#x521B;建进程时有一个初始值，之后会根据情况动态地调整优先级

**如何合理设置各类进程的优先级？**

* 系统进程优先级**高于**用户进程
* 前台进程优先级**高于**后台进程
* 操作系统更**偏好 I/O 型进程**（I/O 繁忙型进程）
  * I/O设备和CPU可以并行工作。如果优先让I/O繁忙型进程优先运行的话，则越有可能让I/O设备尽早地投入工作，则资源利用率、系统吞吐量都会得到提升

**如果采用的是动态优先级，什么时候应该调整？**

* 可以从追求公平、提升资源利用率等角度考虑
* 如果某进程在就绪队列中等待了很长时间，则可以适当提升其优先级
* 如果某进程占用处理机运行了很长时间，则可适当降低其优先级
* 如果发现一个进程频繁地进行I/O操作，则可适当提升其优先级

### 例子（非抢占式）

![](/files/-MF1E7xrImVUY09nEVAd)

### 例子（抢占式）

![](/files/-MF1EGg7smZ3StchhREO)

## 13. 多级反馈队列调度算法

* **算法思想：**&#x5BF9;其他调度算法的折中权衡
* **算法规则：**
  1. 设置多级就绪队列，各级队列优先级从高到低，时间片从小到大
  2. 新进程到达时先进入第 1 级队列，按 FCFS 原则排队等待被分配时间片，若用完时间片进程还未结束，则进程进入下一级队列队尾。如果此时已经是在最下级的队列，则重新放回该队列队尾
  3. 只有第 k 级队列为空时，才会为 k + 1 级队头的进程分配时间片
* **用于作业 / 进程调度：**&#x7528;于进程调度
* **是否可抢占：抢占式**的算法。在 k 级队列的进程运行过程中，若更上级的队列（1 \~ k - 1 级）中进入了一个新进程，则由于新进程处于优先级更高的队列中，因此新进程会抢占处理机，原来运行的进程放回k 级队列队尾
* **优缺点：**
  * 对各类型进程相对公平（FCFS 的优点） ；每个新到达的进程都可以很快就得到响应（RR 的优点）；短进程只用较少的时间就可完成（SPF 的优点）；不必实现估计进程的运行时间（避免用户作假）；可灵活地调整对各类进程的偏好程度，比如 CPU 密集型进程、I/0 密集型进程（拓展：可以将因 I/O 而阻塞的进程重新放回原队列，这样 I/O 型进程就可以保持较高优先级）
* **是否会导致饥饿：** 会

### 例子

![](/files/-MF1HbBhqFkzp6WTbm5X)
