第七章 进程调度
本章主要分为三个部分:
- 调度策略从理论上介绍Linux的进程调度。
- 调度算法介绍实现调度所采用的数据结构和相应算法。
- 与调用相关的系统调用介绍影响进程调度的系统调用。
7.1 调度策略
Unix系统的调度主要要去实现的目标有:
- 进程的相应时间要尽可能的少。
- 进程的后台作业的吞吐量要尽可能的大。
- 要尽量避免进程的饥饿现象。
- 要兼顾好高优先级和低优先级。
而一个系统如何实现上述这些目标的方法就是系统的调度策略。
Linux调度的基本思想是:时分复用。即把处理器时间分为若干份分给需要运行的进程。每份时间叫做“片”或“时间片”。
Linux的调度策略也根据优先级来区分调度各个进程。并且优先级是动态的。当进程已经等待很久了,就适当提高其优先级。同样,如果一个进程已经轮询了好多次了,就适当降低它的优先级,降低它的轮询频率。
另外,从进程的资源耗费方面可以分为I/O受限(I/O-bound)进程和CPU受限(CPU-bound)进程。
前者是指进程需要频繁的使用I/O设备。后者需要大量的CPU计算。
从进程作用方面看,进程又可以分为:
- 交互式进程(interactive process):例如键盘、鼠标的处理进程。
- 批量进程(batch process):例如编译等进程。
- 实时进程(real-time process):要求时效性比较强。例如传感器进程等。
系统调用 | 说明 |
---|---|
nice | 略 |
… | … |
7.1.1 进程的抢占
Linux的进程调度是抢占式的。
即如果某一个进程进入到TASK_RUNNING
状态时,会与当前正在运行的进程的优先级进行比较。如果优先级比当前进程高的话,就中断当前的进程,然后切换到新进程。
7.1.2 时间片的持续时间
时间片的持续时间不能太长也不能太短。
因为进程切换也是需要耗费时间的,所以,太短的时间片会造成进程的过于频繁的切换,从而造成大量的资源都用在了进程切换上了。
太长的时间片也是不好的,因为时间片过于长会影响到系统的响应。
7.2 调度算法
进程都是按照以下类型进行调度的:
- SCHED_FIFO:先入先出实时进程
- SCHED_RR:时间片轮转实时进程
- SCHED_NORMAL:普通分时进程
7.2.1 普通进程的调度
普通进程都有自己的静态优先级,范围从大到小为:139~100。
新进程总是继承其父进程的静态优先级。不过可以通过nice()
和setpriority()
改变自己的静态优先级。
7.2.1.1 基本时间片
基本时间片的计算公式如下:
由公式可看出,基本时间片与静态优先级是有直接关系的,优先级越高,时间片越大。
7.2.1.2 动态优先级和平均睡眠时间
动态优先级 是调度程序在调度新进程时的参考优先级。范围也是(139~100)。其公式为:
dynamic priority = max (100, min ( static priority - bonus + 5, 139)) (2)
bounus的取值范围为0 ~ 10,即(-bounus+5)的取值范围为-5 ~ 5。根据bounus的值增加或减小进程的动态优先级。bonus的值与进程的历史状态有关。即进程的平均休眠时间有关。
7.2.1.3 活动或过期进程
活动进程是指还没有用完时间片的进程。
过期进程是指已经用完时间片的进程。
过期进程不能运行,知道所有的活动进程都过期。主要是为了防止进程进入饥饿状态。
7.2.2 实时进程的调度
每个实时进程都有一个范围为(0 ~ 99)的实时优先级。
实时进程总是作为活动进程存在。
7.3 调度程序所使用的数据结构
7.3.1 runqueue数据结构
每个CPU都要自己的运行队列。
7.3.2 进程描述符
7.4 调度程序所使用的函数
略
7.5 多处理器中得到运行队列的平衡
Linux采用SMP(对称多处理器)模型。
以下是SMP的类型:
- 标准的多处理器体系结构
- 超线程
- NUMA
这些类型可以混合使用。
一般一个cpu只会调度自己的运行队列中的进程。这样就有可能造成一核有难,八核围观的线性。所有做好平衡是很重要的。
7.5.1 调度域
调度域是用来实现负载均衡的重要方式。
调度域实际上是一个CPU集合。他的工作量应当由内核保持平衡。
调度域采用分层结构:最上层的调度域通常包含系统中的所有CPU,其包含好多个子调度域。每个子调度域中又包含一个CPU子集。