进程调度

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

进程调度一般发生在一下几种情况下:

在非抢占式调度中,进程开始执行以后,除非它主动放弃CPU或被block, 否则就能一直执行。

抢占式调度中,如果在进程执行过程中来了一个优先级更高的进程,CPU使用权就会被抢走,尤其在时间片调度中即使时间片没用完也可以被抢占。但抢占也不是随时可以发生的,如果设计不好可能会发生优先级逆转或者死锁问题。

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

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

Balance : 让系统的各个组件都能得到最大程度的利用率

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

Turnaround Time :一般在批处理系统中,一个批任务从提交到结束的间隔时间

CPU Utilization :CPU的利用率

Waiting Time :进程在ready队列里等待的时间

Response Time :一般在交互式系统中,从用户提交任务到第一次得到响应(任务不一定完成)的间隔时间

Meeting Deadline :一般在实时系统中及时处理数据,避免丢失或失效

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

1. FCFS : First Come, First Served

这是一种非抢占式的先来先服务算法。ready process队列只有一个。如果进程执行中被block,进入block队列,ready之后作为新的进程排到ready队列的尾部。

优点:容易理解,容易实现

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

2. SJF: Shortest Job First

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

3. Shortest Remaining Time Next

是SJF的抢占式版本,只要有新任务到达就重新调度选择剩余时间最短的任务执行。

SJF和Shortest Remaining Time Next的问题在于一般情况下很难判断进程的剩余执行时间是多少。除非这是经常要执行的task,根据对历史的统计分析能确定一个执行时间的大致范围。

1. Round-Robin Scheduling

轮询调度。 给每个进程相同的时间片,轮流执行。一般时间片选择在20-50msec比较合适,太短会导致进程切换浪费时间,太长会导致响应时间延长。

优点:比SJF响应快

缺点:turnaround时间长

2. Priority Scheduling

优先级调度为每个进程分配优先级,高优先级先执行,这也是时间片调度算法。优先级可以静态分配也可以动态分配,为了避免高优先级的进程一直占用CPU不放,可以在依次执行结束后降低其优先级。相同优先级的进程之间可以使用其他的调度算法如round-robin,不同队列可以使用不同的调度算法。

优点:引入了优先级

3. Multiple Queues

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

4. Guaranteed Scheduling

前面提到的算法都不保证进程能够得到的CPU时间,但有些情况下我们需要确保进程使用CPU的机会和时间,比如n个用户同时登录,一般要保证每个用户都能获得1/n的CPU,或者我们购买VPN服务,根据不同的用户级别需要获得一定的带宽保证。这种算法就叫Guaranteed 调度。在实现中,需要追踪给每个进程分配的CPU,与承诺分配量比较,比值最小的进程会获得下一次使用权。

5. Lottery Scheduling

彩票调度算法引入了随机性,为每个进程发一张彩票,调度时就像开奖,谁中奖谁获得资源。优先级更高的进程可以获得多张彩票以提高中奖机会。

彩票调度有趣的地方在于进程之间可以互赠彩票,比如process 1 pending在process 2上,它可以把自己的彩票都给process2提高它被调度的机会。process2结束以后再把彩票还给process1.

6. Fair-Share Scheduling

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

实时系统分两种:

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

调度算法只能由操作系统实现吗,关于使用哪种调度算法进程是否有话语权呢?答案是可以的。将机制与策略分离,由操作系统提供多种实现机制,并提供system call由process传参数给OS指定具体使用哪一种调度策略。

如果线程是在用户态实现的,那么需要两级调度,OS负责调度process,process负责调度thread。如果线程是在内核态实现的,OS直接调度thread,而不关心它属于哪个process。