1、多任务
- 什么是多任务操作系统?
能同时并发地交互执行多个进程。注意是并发而不是并行。特别地,在多处理机机器上可以实现真正意义上的并行,因为它长了多个脑子 - 多任务操作系统有哪些分类?
非抢占式多任务(cooperative multitasking)和抢占式多任务(preemptive multitasking) - 什么是抢占式多任务?
在该模式下,调度程序可以决定哪个进程停止,这个强制的挂起动作称作为抢占(preemption),这么做的目的是把处理机让给更应该被执行的进程。还有一个名词称作为时间片(timeslice),它是分配给每个可运行进程的处理器时间段。Linux内核是抢占式多任务操作系统 - 什么是非抢占多任务?
除非是进程自己停下来,否则它会一直执行,进程主动挂起的操作称作为让步(yielding)。这个不重要,Linux内核不是这样的。
2、Linux的进程调度
- Linux的进程调度的算法是什么?
- Linux 2.4 非常简陋
- Linux 2.5 O(1)调度程序;适用于大服务器的工作负载,不适用于有很多交互程序需要运行的桌面系统
- Linux 2.6 反转楼梯最后期限调度算法(Rotating Staircase Deadline scheduler)(RSDL) 解决了Linux 2.5的缺点
- Linux 2.6.23 更名为:完全公平调度算法(Completely Fair Schduler)(CFS)
3、策略
进程调度策略决定了进程运行的时机
- I/O消耗型和处理器消耗型的进程
- 什么是I/O消耗型进程?
大部分时间用来提交I/O请求或者是等待I/O请求,例如:多数用户图形界面程序(GUI) - 什么是处理器消耗型进程?
大部分时间用于执行代码上,除非被抢占,否则会一直不断运行。例如:MATLAB - Linux进程调度策略更倾向于哪种进程?
更倾向于I/O消耗型程序,以提供更好的程序响应速度。但调度程序也并未忽略处理器消耗型的进程 - 调度策略需要解决的矛盾是什么?
寻找二者的平衡:进程响应速度(响应时间短)& 最大系统利用率(高吞吐量)
- 什么是I/O消耗型进程?
- 进程优先级
- 设置进程优先级有什么用?
用户和系统都可以通过设置进程的优先级来影响系统的调度。具体的调度策略后面会讲。 - Linux采用了几种优先级范围?
两种,分别是nice值和实时优先级。 - 什么是nice值?
在Linux系统中,nice值代表时间片的比例。nice值的范围是[-20,19],数值越低表明进程优先级越高。 - 什么是实时优先级?
实时优先级的范围是[0,99],数值越高表明进程优先级越高。任何实时进程的优先级都高于普通进程,也就是说实时优先级和nice优先级处于两个互不相交的范畴。 - 感悟
很显然,有实时要求的进程肯定比普通进程来更重要。
- 设置进程优先级有什么用?
- 时间片
- 什么是时间片?
时间片是一个数值,它表明进程在被抢占前所能持续运行的时间。 - Linux调度器分配时间片的方式是什么?
Linux的CFS调度器并没有直接分配时间片到进程,而是将处理器的使用比例划分给了进程。此外,这个比例也会收到进程nice值的影响,进程优先级越高能抢得更多的比例,反之亦反。 - 如何判断当前进程是否可以被抢占?
if(新可运行程序消耗的处理器时间比 < 当前运行的进程) 新进程立刻投入运行,抢占当前进程。
else 推迟新可运行程序运行。
- 什么是时间片?
- 调度策略的活动
一句话:CFS要平衡I/O消耗型进程和处理机消耗型进程。CFS总是会毫不犹豫地让I/O消耗型进程在需要时被投入运行,而处理机消耗型进程则只能在剩下的时刻运行。
4、Linux调度算法
- 调度器类
- 什么是调度器类?
调度器类允许不同类型的进程可以有针对性地选择调度算法。 - 为什么要引入上面这个概念?
完全公平调度(CFS)就是一个针对普通进程的调度类,这个是本节的重点内容。
- 什么是调度器类?
- Unix系统中的进程调度
- Unix系统中的进程调度是什么样子的?
在Unix系统上,进程调度与进程优先级(nice值)和时间片这两个概念密切相关,这样会出现一个影响公平性的问题——分配绝对的时间片引发了固定的切换频率。那么就引入了下面关于CFS的讨论。
- Unix系统中的进程调度是什么样子的?
- 公平调度(CFS)
- CFS的出发点是什么?
进程调度的效果如同系统具备一个理想中的完美多任务处理器,在这个系统中,每个进程能获得1/n的处理器时间(n为进程数量),并且系统调度给他们无限小的时间周期。 - 现实中CFS是什么样的?
允许每个进程运行一段时间,循环轮转、选择运行最少的进程作为下一个运行进程,不再采用时间片分配方式。 - CFS还关心时间片吗?
当然,为了计算准确的时间片,CFS为完美多任务中的无限小调度周期的近似值设置了一个目标——“时间延迟”。例如:将时间延迟设置为20ms,则如果有4个同样优先级的任务,每个任务运行时间为5ms。 - 接着上面的问题,当可运行任务数量趋于无限,则它们各自所获得的处理器比和时间片都将趋于0,这样回导致巨大的进程切换消耗时间。所有,如何解决这个问题?
CFS引你入每个进程获得的时间片底线——最小粒度,默认为1ms,这样可以确保进程切换的额消耗时间在合理的范围内。 - nice值在CFS中的用处是什么,具体的用法?
作为进程获得处理器运行比的权重。任何进程所获得的处理器时间是由他自己和其他可运行进程nice值的差值决定的,而不是绝对值。例如:时间延迟设置为20ms。P1的nice为0,P2的nice为5,则它们获得15ms和5ms的处理器时间。P1的nice为10,P2的nice为15,则它们还是获得15ms和5ms的处理器时间。
- CFS的出发点是什么?
5、Linux调度的实现
- 时间记账
- 调度器实体结构(略)
- 虚拟实时
- 什么是
vruntime
变量
vruntime
变量存放进程的虚拟运行时间,CFS使用vruntime
变量记录一个程序到底运行了多长时间以及它还应该再运行多久。
- 什么是
- 进程选择
- 如何选择进程?
选择具有最小vruntime
的任务运行。 - 如何找到最小
vruntime
的进程?
CFS使用红黑树来组织可运行进程队列,并利用其迅速找到最小vruntime
值的进程。
- 如何选择进程?
- 调度器入口
进程调度的主要入口点函数是schedule()
,它的作用是选择哪个进程可以运行,何时将其投入运行。 - 睡眠和唤醒
- 什么是睡眠?
就是进程阻塞。比如:进程在获取键盘输入时需要等待,此时进程把自己标记为休眠状态。从可执行红黑树中移除,放入等待队列。 - 什么是唤醒?
就是睡眠的逆过程。进程被设置为可执行状态,然后从等待队列移到可执行红黑树中。 - 如何形象理解睡眠与唤醒?
- 什么是睡眠?
6、抢占和上下文切换
- 上下文切换
- 什么是上下文切换?
从一个可执行进程切换到另一个可执行进程的过程。由<kernel/sched.c>
中的context_switch()
函数负责处理。 - 什么时候由谁调用
context_switch()
函数?
当一个新的进程被选处理准备投入运行的时候,schedule()
就会调用该函数。 context_switch()
函数具体完成了哪些工作?- 调用声明在
<asm/mmu_context.h>
中的switch_mm()
,负责把虚拟内存从上一个进程映射切换到新进程中。 - 调用声明在
<asm/system.h>
中的switch_to()
,该函数负责从上一个进程的处理器状态切换到新进程的处理器状态。
- 调用声明在
- 内核怎么知道在什么时候调用
schedule()
?
内核提供了一个重要的标志——need_resched
,用于表明是否需要重新执行一次调度。 need_resched
标志什么时候会被设置?- 当某个进程应该被抢占时,
scheduler_tick()
就会设置这个标志。 - 当一个优先级高的进程进入可执行状态的时候,
try_to_wake_up()
也会设置这个标志
- 当某个进程应该被抢占时,
- 每个进程都有
need_resched
标志吗?
是的,因为访问进程描述符内的数值要比访问全局变量快(current
宏速度很快并且进程描述符通常在高速缓存里)
- 什么是上下文切换?
- 用户抢占
- 什么是用户抢占?
内核即将返回用户空间的时候,如果need_resched
标志被设置,就会导致schedule()
被调用,此时就会发生用户抢占。 - 什么时候产生用户抢占?
- 从系统调用返回用户空间时
- 从中断处理程序返回用户空间时
- 什么是用户抢占?
- 内核抢占
- 什么是内核抢占?
如果没有持有锁,正在执行的代码是可以重新导入的,也就是可以抢占的。具体来讲就是:need_resched
被设置并且preempt_count
为0(preempt_count
表征上锁的次数。上锁+1,解锁-1) - 什么时候产生内核抢占?
- 中断处理程序正在执行,且返回内核空间之前
- 内核代码再一次具有可抢占性的时候
- 内核中的任务显式调用
schedule()
- 内核中的任务阻塞(同样会导致调用了
schedule()
)
- 什么是内核抢占?
7、实时调度策略
- Linux提供了那种实时调度策略?它们被CFS调度器管理吗?
Linux提供了两种实时调度策略:SCHED_FIFO
和SCHED_RR
,它们不被CFS调度器管理,而是被一种特殊的实时调度器管理。 - Linux非实时调度策略是什么?
SCHED_NORMAL
- 什么是
SCHED_FIFO
调度算法?SCHED_FIFO
实现了先入先出的调度算法,不使用时间片。SCHED_FIFO
级的进程比任何SCHED_NORMAL
级的进程优先级高。只要有SCHED_FIFO
级进程在执行,其他级别更低的进程只能等待它变成不可运行状态后才有机会执行。- 只有更高优先级的
SCHED_FIFO
或SCHED_RR
才能抢占SCHED_FIFO
任务 - 如果多个同优先级的
SCHED_FIFO
级进程,它们会轮流执行。 SCHED_FIFO
级进程处于可执行状态,就会一直执行下去,直到自己受到阻塞或者显式地释放处理器为止。
- 什么是
SCHED_RR
调度算法?SCHED_RR
调度算法是带有时间片的SCHED_FIFO
,即SCHED_RR
是一种实时轮转调度算法。- 时间片只能用来重新调度同一优先级的进程,当
SCHED_RR
任务耗尽它的时间片时,在同一优先级的其他实时进程被轮流调度。 - 对于
SCHED_RR
进程,高优先级总是立即抢占低优先级,但低优先级决不能抢占高优先级任务,即便时间片耗尽。
- 什么是软实时,什么是硬实时,Linux提供的是哪种?
- Linux的实时调度算法提供了一种软实时的工作方式
- 软实时:内核调度进程,尽力使进程在它的限定时间到来之前运行,但内核不保证总能满足这些进程的要求。
- 硬实时:保证在一定条件下,可以满足任何调度的要求。
- 实时优先级的调度范围是多少?
[0,MAX_RT_PRIO-1],默认MAX_RT_PRIO
为100,即默认为[0,99] SCHED_NORMAL
级进程的nice
值与前一个问题有何关联?
SCHED_NORMAL
级进程的nice
值共享了实时优先级的取值空间。它的范围使[MAX_RT_PRIO,MAX_RT_PRIO+40],即默认为实时优先级的[100,139],对应nice值的范围为[-20,19]
8、与调度相关的系统调用
略