进程调度的概念

来源:互联网 发布:慕课网 java视频教材 编辑:程序博客网 时间:2024/04/30 21:56
 

从本博开始,我们就要慢慢深入到进程管理乃至整个内核的核心概念——进程调度里边了。这里,先把相关概念理一理。

 

刚接触Linux,我们就讲了,它是一个分时系统,却由具备实时系统的特性。所以与任何分时系统一样,通过一个进程到另一个进程的快速切换,达到表面上看来多个进程同时执行的神奇效果。我们已经在前面的博文中讲过了进程切换的本身已,从本博开始,我们将进入进程管理最最最重要的部分——进程的调度,主要关心什么时候进行进程切换及选择哪一个进程来运行。

借鉴了ULK-3的方法,为了叙述起来更简单,我们仍以 80X86体系结构为例,尤其是,我们假定系统采用统一内存访问模型(Uniform Memory Access),而且系统时钟设定为1ms。

1 调度策略


Linux的调度基于分时技术(time-sharing)。我先来大体说说这个技术的内涵:

多个进程以“时间多路复用”方式运行,因为CPU的时间被分成“片(slice)”,给每个可运行进程分配一片。单处理器在任何给定的时刻只能运行一个进程,如果当前运行进程的时间片或时限(quantum)到期时,该进程还没有运行完毕,则进程切换就可以发生。 分时依赖于定时中断,具体来说就是我们在中断处理专题中讲过的那个位于arch/i386/kernel/time.c文件中著名的timer_interrupt中断服务函数。因此,对所有的进程是透明的,不需要在程序中插入额外的代码来保证CPU分时。

第一次读这句话肯定会不解,没关系,可以通过理解具体的实现后,再来读这样的概括性的文字,就好理解了。继续往下走,定时中断就像心脏起搏器那样驱动着进程调度,同时调度策略也是根据进程的优先级对它们进行分类。有时用复杂的算法求出进程当前的优先级,但最后的结果是相同的:每个进程都与一个值相关联,这个值表示把进程如何适当地分配给CPU。

在Linux中,进程的优先级是动态的。 调度程序跟踪进程正在做什么,并周期性地调整它们的优先级。 在这种方式下,在较长的时间间隔内没有使用CPU的进程,通过动态地增加它们的优先级来提升它们被调度的可能性。相应地,对于已经在CPU上运行了较长时间的进程,通过减少它们的优先级来处罚它们。

2 进程抢占


下一个比较重要的概念是——进程抢占。

Linux的进程是抢占式的,什么意思?如果进程进入TASK_RUNNING状态(通常是刚刚变为可运行的进程),内核检查它的动态优先级(这里千万要注意,内核是通过动态优先级来判断的,而用户只能通过系统调用来设置进程的静态优先级 )是否大于当前正运行进程的优先级。如果是,current的执行被中断,并调用调度程序选择另一个进程运行。另一种情况,当进程在它的时间片到期时也可以被抢占。此时,当前进程thread_info结构中的TIF_NEED_RESCHED标志被设置,以便定时中断处理程序终止时调度程序被调用。

可能还是没有说清楚,那让我们考虑一个例子吧:如果只有两个程序—一个文本编辑程序和一个内核进程(kswapd)正在执行。 文本编辑程序是一个交互式程序,因此,它的动态优先级高于kswapd。 不过,因为编辑程序交替于暂停思考与数据输入之间,因此,它经常被挂起;此外,两次击键之间的平均延迟相对较长。 所以,只要用户一按键,中断就发生,内核唤醒文本编辑进程。 内核也确定编辑进程的动态优先级确实是高于current的优先级(当前正运行的进程,即kswapd),因此,编辑进程的TIF_NEED_RESCHED标志被设置,如此来强迫内核处理完中断时激活调度程序。调度程序选择编辑进程并执行进程切换;结果,编辑进程很快恢复执行,并把用户敲的字符回显在屏幕上。当处理完字符时,文本编辑进程自己挂起等待下一次击键,kswapd恢复执行。

注意被抢占的进程并没有被挂起,因为它还处于TASK_RUNNING状态,只不过不再使用CPU。此外,记住,Linux2.6内核是抢占式的,这意味着进程无论是处于内核态还是用户态,都可能被抢占。

3 时间片


再讲一个概念——时间片。

时间片就是CPU分给某个进程的时间。在进程的描述符中,有一个很重要的字段:
task->time_slice

它是进程的时间片还剩余的时钟节拍。我们多次提过了,定时器中断就像一个心脏起搏器一样,每次时钟中断,就减少它一个节拍,当它为0的时候就执行调度。

那么时间片的长短对系统性能就很关键了:它既不能太长也不能太短。

如果平均时间片太短,由进程切换引起的系统额外开销就变得非常高。例如,假定进程切换需要5ms,如果时间片也是5ms,那么,CPU至少把50%的时间花费在进程切换上。

如果平均时间片太长,进程看起来就不再是并发执行。 例如,让我们假定把时间片设置为5秒,那么,每个可运行进程运行大约5秒,但是暂停的时间更长(典型的是5秒乘以可运行进程的个数)。
  
通常认为长的时间片降低交互式应用程序的响应时间,但这往往是错误的。正如前面例子中提到的文本编辑器进程——交互式进程相对有较高的优先级,因此,不管时间片是多长,它们都会很快地抢占并处理进程。

在一些情况下,一个太长的时间片会降低系统的响应能力。例如,假定两个用户在各自的shell提示符下分别输入两条命令,其中一条启动一个CPU受限型的进程,而另一条启动一个交互式应用。两个shell都创建一个新进程,并把用户命令的执行委托给新进程。此外,又假定这样的新进程最初有相同的优先级(Linux预先并不知道执行进程是批处理的还是交互式的)。 现在,如果调度程序选择CPU受限型的进程执行,那么,另一个进程开始执行前就可能要等待一个时间片。因此,如果这样的时间片较长,那么,看起来系统就可能对用户的请求反应迟钝。

时间片大小的选择总是一种折衷。Linux采取单凭经验的方法,即选择尽可能长、同时能保持良好响应时间的一个时间片。

4 调度算法


最后的概念就是我们本专题的核心概念 —— 调度算法

早期Linux版本中的调度算法非常简单易懂:在每次进程切换时,内核扫描可运行进程的链表,计算进程的优先权,然后选择“最佳”进程来运行。这个算法的主要缺点是选择“最佳”进程所要消耗的时间与可运行的进程数量相关,因此,这个算法的开销太大,在运行数千个进程的高端系统中,要消耗太多的时间。

Linux 2.6的调度算法就复杂多了。通过设计,该算法较好地解决了与可运行进程数量的比例关系,因为它在固定的时间内(与可运行的进程数量无关)选中要运行的进程。它也很好地处理了与处理器数量的比例关系,因为每个CPU都拥有自己的可运行进程队列。而且,最最关键的是,新算法较好地解决了区分交互式进程和批处理进程的问题。因此,在高负载的系统中,用户感到在Linux2.6中交互应用的响应速度比早期的Linux版本要快。

每个Linux进程总是按照下面的调度类型被调度:位于每个task_struct结构的policy字段

SCHED_FIFO

先进先出的实时进程。当调度程序把CPU分配给进程的时候,它把该进程描述符保留在运行队列链表的当前位置(最前面)。如果没有其他可运行的高优先权实时进程,进程就继续使用 CPU,想用多久就用多久,即使还有其他具有相同优先权的实时进程处于可运行状态。

SCHED_RR

时间片轮转的实时进程。当调度程序把CPU分配给进程的时候,把该进程的描述符放在运行队列链表的末尾。这种策略保证对所有具有相同优先权的SCHED_RR实时进程公平地分配CPU时间。

SCHED_NORMAL

普通的分时进程,下一篇博文将详细探讨。

调度算法根据进程策略是普通进程还是实时进程而有所不同,这里只要晓得概念就行了,下一篇博文,我们就将详细讨论具体的实现过程。

 

转载: http://blog.csdn.net/yunsongice/article/details/5526175