进程调度

当计算机中有多个进程处于就绪状态时,CPU应该分配给哪个进程?操作系统中做出这个决策的组件就是调度器,决策算法叫做调度算法,决策过程就是进程调度的过程。

进程调度通常发生在以下情况:

在非抢占式调度中,进程开始执行后,除非它主动放弃CPU或者被阻塞,否则它总是可以执行的。

在抢占式调度中,如果一个优先级更高的进程在执行过程中到来,CPU的使用权就会被拿走,尤其是在时间片调度中,即使时间片没有用完。但是抢占不是任何时候都能发生的,设计不好可能会发生优先级反转或者死锁。

在不同的场景下,为了达到不同的目标,评价调度算法的标准是不同的。这里我们介绍一些常用的标准:

公平:给每个进程一个公平使用CPU的机会。

平衡:使系统的所有组件得到最大的利用。

吞吐量吞吐量:单位时间内完成的任务数。

周转时间:一般来说,在批处理系统中,提交和完成一个批处理任务之间的时间间隔。

CPU利用率:CPU CPU的利用率。

等待时间:流程在就绪队列中等待的时间。

响应时间:一般来说,在交互系统中,用户提交任务到第一次得到响应的间隔时间(任务可能没有完成)。

会议截止日期:一般情况下,数据在实时系统中处理,以避免丢失或失效。

接下来,让我们看看三种不同类型的系统中常用的调度算法。

1.先来先服务

这是非抢占式的先来先服务算法。只有一个就绪流程队列。如果进程在执行过程中被阻塞,它将进入阻塞队列,然后它将作为一个新的进程排队到就绪队列的末尾。

优点:易于理解和实现。

缺点:平均等待时间往往很长,不利于平衡CPU密集型和IO密集型进程。

2.SJF:最短的工作优先

SJF也是非抢占式调度,每次都选择最短的任务来执行。

3.下一个最短剩余时间

它是SJF的一个抢占式版本,当一个新任务到达时,它会重新调度并选择剩余时间最短的任务。

SJF和最短剩余时间Next的问题是,通常很难判断流程的剩余执行时间。除非这是一个需要频繁执行的任务,否则可以根据历史的统计分析来确定执行时间的大致范围。

1.循环调度

轮询调度。给每个进程相同的时间片,依次执行。时间片一般为20-50msec,太短会导致进程切换浪费时间,太长会导致响应时间延长。

优势:比SJF反应更快

缺点:周转时间长。

2.优先级调度

优先级调度给每个进程分配优先级,高优先级先执行,也是一种时间片调度算法。优先级可以静态或动态分配。为了防止高优先级进程一直占用CPU,可以在顺序执行后减少。在具有相同优先级的进程之间可以使用其他调度算法,例如循环调度,并且不同的调度算法可以用于不同的队列。

优点:优先介绍。

3.多个队列

为了避免执行时间长的进程频繁的进程切换,可以在不同的优先级队列之间分配不同长度的时间片。流程执行一次后,会被分配执行时间更长的其他优先级。比如一个进程需要100个量程,第一次执行分配1,下次执行分配2,下次执行分配4,8,16,32,64。与每次只分配1的纯轮询算法相比,减少了进程调度的次数。

4.保证调度

上面提到的算法都不能保证进程能够得到的CPU时间,但是在某些情况下,我们需要保证进程使用CPU的机会和时间。比如n个用户同时登录,一般需要保证每个用户能够获得1/n个CPU,或者我们可以购买VPN服务,根据不同的用户级别获得一定的带宽保障。这种算法被称为保证调度。在实现中,需要跟踪分配给每个进程的CPU。与承诺分配相比,比例最小的进程将获得下一次使用权。

5.彩票时间安排

彩票调度算法引入了随机性,为每个进程发行一张彩票。排班就像彩票,谁中了彩票谁就得到资源。优先级较高的进程可以获得多张彩票,提高中奖几率。

彩票调度的有趣之处在于,进程可以互相赠送彩票。例如,进程1 pending在进程2上,它可以将其所有彩票交给进程2,以提高其被调度的机会。在process2之后将彩票返回到process1。

6.公平份额调度

让我们考虑一种情况,所有进程都不属于一个用户,这在Linux系统中很常见。如果user1有99个进程,user2只有1个进程,按照前面的算法,user1可能得到99%的CPU,而user2只有1%。为了实现用户级的公平性,在调度时需要考虑进程属于哪个用户。

有两种实时系统:

在实时系统中,任务时间一般较短,调度器需要使所有进程在截止日期前完成。对于周期性发生的事件,如果事件的周期为,则事件处理时间(需要占用CPU的时间)为,只有这样才可以调度。

调度算法只能由操作系统实现吗?流程有没有权力说要用哪种调度算法?答案是肯定的。机制与策略分离,操作系统提供多种实现机制,并提供系统调用,进程传递参数给OS指定使用哪个调度策略。

如果线程是在用户模式下实现的,那么就需要两级调度,OS负责调度进程,进程负责调度线程。如果线程是在内核模式下实现的,操作系统直接调度线程,而不管它属于哪个进程。