Linux进程(四)系统中进程调度详解

1.1进程调度的基本原理

1.1.1进程调度的功能

进程调度的功能是按照一定的策略把CPU分配给就绪进程,使他们轮流地使用CPU。进程调度实现看教程的就绪态与运行态之间的装换。调度工作包括:

    (1)当正运行的教程因某种原因放弃CPU时,为该进程保留现场信息。

    (2)按一定的调度算法,从就绪进程中选一个进程,把CPU分配给它。

    (3)为被选中的进程恢复现场,使其运行。

1.1.2进程调度算法

进程调度算法是系统效率的关键,它确定了系统对资源,特别是对CPU资源的分配策略,因而直接决定着系统最本质的性能指标,如响应速度、吞吐量等。进程调度算法的目标首先是要充分发挥CPU的处理能力,满足进程对CPU的需求。此外还要尽量做到公平对待每个进程,是他们都能得到运行机会。

常用的调度算法:

(1)先进先出法:按照进程在就绪队列中的先后次序来调度。这是最简单的调度法,缺点是对一些紧迫任务的响应时间过长

(2)短进程优先发:有先调用短进程运行,以提高系统的吞吐量,但对长进程不利。

(3)时间片轮转法:进程按规定的时间片轮流使用CPU。这种方法可满足分时系统对用户响应时间的要求,有很好的公平性。时间片长度的选择应适当。过短会引起频繁的进程调度,过长则对用户的响应较慢。

(4)优先调度法:为每个进程设置优先级,调度时先选择优先级高的进程运行,使紧迫的任务可以优先得到处理。静态优先级是指预先指定的,动态优先级则随进程运行时间的长短而降低或升高。两种优先级组合调度,即可保证对高优先级进程的响应,也不会忽略低优先级的基础。

1.2 Linux系统的进程调度

1.2.1 进程的调度信息

在Linux系统中,进程的PCB中记录了与基础调度相关的信息,主要有:

  1. 调度策略(policy):对进程的调度算法。决定了调度程序应如何调度该进程。Linux系统将进程分为实时进程与普通(非实时)进程。实时进程是那些对响应时间要求很高的进程,如视频与音频应用、过程控制和数据采集等,系统优先响应它们对CPU的要求;普通进程则采用优先级+时间片轮转的调度策略,以兼顾系统的响应速度,公平性和整体效率。

  2. 实时优先级(rt_priority):实时进程的优先级,标志实时进程优先权的高低,取值范围为1(最高)~99(最低)

  3. 静态优先级(static_prio):进程的基本优先级。进程在创建指之初被赋予了一个表示优先度的“nice数”,它决定了进程的静态优先级。静态优先级的取值返回为100(最高)~139(最低),它是计算时间片的依据。

  4. 动态优先级(prio):普通进程的实际优先级。它是对静态优先级的调整,随进程的运行状况而变化,取值范围是100(最高)~139(最低)

  5. 时间片(time_slice):进程当前剩余的时间片。实际片的初始大小却决于进程的静态优先级,优先级越高则时间减为0的基础将不会被调度,直达它再次获得新的时间片。

    基础的调度策略和优先级等是在进程创建时从父进程那里继承来的,不过用户可以通过系统调用它们。

    setpriority()和nice()用于设置静态优先级;

    sched_setparam()用于设置实时优先级;

    sched_setscheduler()用于设置调度策略和参数。

1.2.2 调度函数和队列

Linux系统中用于实现进程调度的程序时内核函数schedule()。该函数的功能时按照预定的策略在可执行进程中选择一个进程,切换CPU现场使之运行。调度程序中最基本的数据结构是可执行队列runqueue。每个CPU都有一个自己的可执行队列,它包含了所有等待该CPU的可执行进程。runqueue结构中设有一个curr指针,指向正在使用CPU的进程。进程切换时,curr指针也跟着变化。

旧版本的调度程序(2.4版内核)在选择进程时需要遍历整个可执行队列,用的时间随进程数量的增加而增加,最坏时可能达到O(n)复杂度级别。新内核(2.6版内核)改进了调度的算法和数据结构,使算法的复杂度达到O(1)级(最优级别),故称为O(1)算法。

新内核的runqueue队列结构中实际包含了多个进程队列,它们将进程按优先级划分,相同优先级的链接在一起,成为一个优先级队列。所有优先级队列的头地址都记录在一个优先级数组中,按优先级顺序排列。实时进程的优先级队列在前(1~99),普通进程的优先级队列在后(100~139)。当进程调度选择进程时,只需在优先级数组中选择当前最高优先级队列中的第1个进程即可。无论进程的多少,这个操作总可以在固定的时间内完成,因而是O(1)级别的。

影响调度算法效率的另一个操作是为进程重新计算时间片。旧算法中,当所有进程的时间片用完后,调度程序遍历可执行队列,逐个为它们重新赋予时间片,然后开始下一轮的执行。当进程数目很多时,这个过程会十分耗时。为克服这个弊端,新调度函数将每个优先级队列分为两个:活动队列和过期队列。活动队列包含了那些时间片未用完的进程,过期队列包含了那些时间片用完的进程。相应地,在runqueue中设置了两个优先级数组,一个是活动数组active,它记录了所有活动队列的指针;另一个是过期数组expired,它记录了所有过期队列的指针。当一个进程进入可执行态时,它被按照优先级放入一个活动队列中;当进程的时间片耗完时,它会被赋予新的时间片并转移到相应的过期队列中。当所有活动队列都为空时,只需将active和expired数组的指针互换,过期队列就成为活动队列。这个操作也是O(1)级别的。 可以看出,新调度的实现策略是用复杂的数据结构来换取算法的高效率的。

1.2.3 Linux的进程调度策略

进程调度在选择进程时,首先在可执行队列中寻找优先级最高的进程。由于实时进程的优先级(1~99)总是高于普通进程(100~139),所以实时进程永远优先于普通进程。选中进程后,根据PCB中policy的值确定该进程的调度策略来进行调度。在schedule()函数中实现了3种调度策略,即先进先出法,时间片轮转法和普通调度法。

1)先进先出法 先进先出(FIFO,First In First Out)调度算法用于实时进程,采用FIFO策略的实时进程就绪后,按照优先级rt_priority加入到相应的活动队列的队尾。调度程序按优先级依次调度各个进程运行,具有相同优先级的进程采用FIFO算法。投入运行的进程将一直运行,直到进入僵死态、睡眠态或者是被具有更高实时优先级的进程夺去CPU。   FIFO算法实现简单,但在一些特殊情况下有欠公平。比如,一个运行时间很短的进程排在了一个运行时间很长的进程之后,它可能要花费比运行时间长很多倍的时间来等待。

2)时间片轮转法 时间片轮转(RR,Round Robin)算法也是用于实时进程,它的基本思想是给每个实时进程分配一个时间片,然后按照它们的优先级rt_priority加入到相应的活动队列中。调度程序按优先级依次调度,具有相同优先级的进程采用轮换法,每次运行一个时间片。时间片的长短取决于其静态优先级static_prio。当一个进程的时间片用完,它就要让出CPU,重新计算时间片后加入到同一活动队列的队尾,等待下一次运行。RR算法也采用了优先级策略。在进程的运行过程中,如果有更高优先级的实时进程就绪,则调度程序就会中止当前进程而去响应高优先级的进程。 相比FIFO来说,RR算法在追求响应速度的同时还兼顾到公平性。

3)普通调度法 普通调度法(NORMAL,Normal Scheduling)用于普通进程的调度。每个进程拥有一个静态优先级和一个动态优先级。动态优先级是基于静态优先级调整得到的实际优先级,它与进程的平均睡眠时间有关,进程睡眠的时间越长则其动态优先级越高。调整优先级的目的是为了提高对交互式进程的响应性。

NORMAL算法与RR算法类似,都是采用优先级+时间片轮转的调度方法。进程按其优先级prio被链入相应的活动队列中。调度程序按优先级顺序依次调度各个队列中的进程,每次运行一个时间片。一个进程的时间片用完后,内核重新计算它的动态优先级和时间片,然后将它加入到相应的过期队列中。与RR算法的不同之处在于,普通进程的时间片用完后被转入过期队列中,它要等到所有活动队列中的进程都运行完后才会获得下一轮执行机会。而RR算法的进程始终在活动队列中,直到其执行完毕。这保证了实时进程不会被比它的优先级低的进程打断。可以看出,RR算法注重优先级顺序,只在每级内采用轮转;而NORMAL算法注重的是轮转,在每轮中采用优先级顺序。

1.2.4 进程调度的时机

当需要切换进程时,进程调度程序就会被调用。引发进程调度的时机有下面几种:   

(1) 当前进程将转入睡眠态或僵死态。   

(2) 一个更高优先级的进程加入到可执行队列中。   

(3) 当前进程的时间片用完。   

(4) 进程从核心态返回到用户态。

从本质上看,这些情况可以归结为两类时机,一是进程本身自动放弃CPU而引发的调度,这是上述第1种情况。这时的进程是主动退出CPU,转入睡眠或僵死态。二是进程由核心态转入用户态时发生调度,包括上述后3种情况。这类调度发生最为频繁。当进程执行系统调用或中断处理后返回,都是由核心态转入用户态。时间片用完是由系统的时钟中断引起的中断处理过程,而新进程加入可执行队列也是由内核模块处理的,因此也都会在处理完后从内核态返回到用户态。

Linux系统是抢占式多任务系统,上述情况除了第1种是进程主动调用调度程序放弃CPU的,其他情况下都是由系统强制进行重新调度的,这就是CPU抢占(preemption)。在必要时抢占CPU可以保证系统具有很好的响应性。为了标志何时需要重新进行进程调度,系统在进程的PCB中设置了一个need_resched标志位,为1时表示需要重新调度。当某个进程的时间片耗尽,或有高优先级进程加入到可执行队列中,或进程从系统调用或中断处理中返回前,都会设置这个标志。每当系统从核心态返回用户态时,内核都会检查need_resched标志,如果已被设置,内核将调用调度函数进行重新调度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dola_Pan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值