Skip to the content.

Scheduling 1: I/O system,Concepts and Classic Policies

I/O and Storage Layers

下图以c语言中的read函数为例,说明了操作是如何一步步的从用户态到内核态,最后通过驱动程序读取位于存储设备中的内容的。

image-20240324142349373

Internal(Kernal) OS File Description

内部数据结构描述文件的所有内容

指针:struct file *file

结构体 file_operations *f_op:描述了此特定设备实现其操作的方式

image-20240324143627081

从上图可知,OS有很多种类型的I/O,如CPU、内存、硬盘、键盘鼠标、网卡等类型的I/O,与这些设备的交互都可以被抽象为与一个文件的交互。

Device Drivers

设备驱动程序:内核中与设备硬件直接交互的设备特定代码

设备驱动程序通常分为两个部分:

Life Cycle of An I/O Request

下图形象的说明了从用户态发起一个I/O操作,该操作经过USER->kernel->Device Driver->Device Hardware之后,再用相反的路径返回,最终用户态的buffer中被填充这个数据的整个过程,十分形象。

image-20240324145528730

Scheduling

Recall:Scheduling

操作系统决定从队列中选择哪个任务执行的决策是调度(Scheduling)的核心内容。调度是指在任意时刻决定哪些线程或进程可以访问系统资源,以及在何时、何地、以何种方式分配这些资源的过程。

通常情况下,调度涉及到以下方面:

  1. CPU 时间调度:最常见的调度方式是决定哪个线程或进程可以在 CPU 上执行。这种调度方式通常根据优先级、调度策略(如先来先服务、最短作业优先、轮转调度、优先级调度等)来决定。
  2. 其他资源的调度:除了 CPU 时间外,操作系统还可能需要考虑其他资源的调度,如网络带宽(Network Bandwidth)和磁盘访问(Disk Access)等。例如,操作系统可能需要决定哪个进程可以获得网络传输的带宽,或者如何管理磁盘的访问以确保公平性和效率。

Scheduling Policy Goals/Criteria

调度策略的目标/标准通常包括以下几个方面:

最小化响应时间

最大化吞吐量

公平性

这些标准通常是调度策略设计中考虑的关键因素,不同的应用场景和系统需求可能会对这些标准产生不同的重视程度。因此,在选择和设计调度策略时,需要综合考虑这些标准,并根据实际情况进行权衡和调整。

响应时间和吞吐量

响应时间和吞吐量通常被认为是两个矛盾的指标,因为它们之间存在一种权衡关系:

响应时间(Response Time)

吞吐量(Throughput)

然而,响应时间和吞吐量之间存在一种权衡关系:

因此,设计和优化操作系统时,需要根据具体应用场景和用户需求,综合考虑响应时间和吞吐量,并在二者之间进行权衡取舍,以实现系统的最佳性能。

一般来说,操作系统的资源利用率越高,系统的吞吐量也往往越大。资源利用率指的是系统中各种资源的有效利用程度,包括 CPU、内存、磁盘等。当资源得到充分利用时,系统可以更快地处理任务,从而提高吞吐量。然而,这并不是绝对的,因为资源利用率的提高可能会导致资源竞争和调度延迟,从而影响系统的响应时间。因此,在实践中需要综合考虑资源利用率和系统的性能指标,以实现最佳的系统性能。

下面开始介绍几种OS的内核线程的调度算法。为什么是OS内核线程,因为之前讲进程的时候提到过,本质上调度做的工作是调度内核中的线程,每个内核线程有一个对应的用户态线程(大多数OS的选择)。

进程和线程的关系

在计算机科学中,进程线程是操作系统中的基本概念,用于管理并发执行的任务。让我们来详细了解一下它们之间的关系和特点。

进程

线程

总之,一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度较小,使得多线程程序具有更高的并发性。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而提高了程序的运行效率.

First-Come, First-Served (FCFS) Scheduling

FCFS(First-Come, First-Served,先来先服务)又称为 FIFO(First In, First Out,先进先出)或者“运行直至完成”,是一种简单的调度算法,其特点是任务按照到达的顺序依次执行,即先到达的任务先被执行,后到达的任务则按照到达的顺序排队等待执行。

FIFO pros and cons

FIFO(First-In, First-Out)调度算法具有以下优点和缺点:

优点

  1. 简单易懂:FIFO 调度算法非常简单,易于实现和理解。
  2. 公平性:任务按照到达的顺序执行,具有公平性,每个任务都有机会得到处理。

缺点

  1. 长任务阻塞短任务:长任务可能会占用 CPU 较长时间,导致短任务需要等待较长时间才能得到执行。这可能会导致短任务的响应时间变长,或者称为“饥饿”现象。
  2. 效率低下:由于长任务的存在,短任务可能需要等待很长时间才能执行,导致系统的整体效率较低。
  3. 不适用于实时性要求高的场景:对于实时性要求高的任务,FIFO 调度算法无法保证其在规定时间内得到执行,可能会影响系统的实时性能。

举个例子,假设在超市购物时,每位顾客都按照到达的顺序排队结账(FIFO 调度),那么如果前面有顾客购物车装满了商品,那么后面的顾客就需要等待较长时间才能结账。尽管这种方法公平简单,但是对于购买少量商品的顾客来说,可能会感到不便,而且可能会耽误他们的时间。

Round Robin (RR) Scheduling(轮询调度算法)

FCFS(First-Come, First-Served)调度方案对短作业可能不利:

与此相反,Round Robin(循环调度)方案采用了抢占式调度(preemption)。

RR pros and cons

Round-Robin(循环调度)方案具有以下优点和缺点:

优点

  1. 适合短作业:Round-Robin 方案更有利于短作业,因为每个作业都会在规定的时间片内得到执行,避免了长作业长时间占用 CPU 导致短作业等待的问题。这提高了系统对短作业的响应速度,使得系统更加灵活和公平。
  2. 公平性:Round-Robin 方案采用了抢占式调度,每个作业都有机会在规定的时间片内执行,从而保证了系统资源的公平分配。

缺点

  1. 上下文切换开销:对于长时间运行的作业,上下文切换的开销会逐渐累积,导致系统的开销增加。由于每个作业都会在时间片结束时被抢占,并且需要保存和恢复其上下文信息,因此当作业的数量增多或时间片过短时,上下文切换的开销可能会成为系统性能的瓶颈。

综上所述,Round-Robin 方案在适用于短作业和保证公平性方面具有明显优势,但对于长时间运行的作业可能会存在上下文切换开销较大的问题。因此,在选择调度方案时,需要综合考虑系统的特点、作业的性质以及用户的需求,以达到最佳的系统性能和用户体验。

How to Implement RR in the Kernel?

在内核中实现Round-Robin(RR)调度算法的主要步骤如下:

  1. 使用 FIFO 队列:与 FCFS 调度算法类似,首先需要使用 FIFO 队列来管理就绪队列中的进程。这样可以确保按照进程的到达顺序进行调度。

  2. 时间片到期的抢占:为了实现时间片到期时的抢占,需要利用定时器中断。内核会设置一个定时器,用来触发时间片的到期事件。当时间片到期时,内核会捕获定时器中断,并执行相应的处理程序来抢占当前正在执行的进程。

  3. 将进程移动到队列末尾:抢占发生后,内核需要将当前正在执行的进程移动到队列的末尾,以确保其他就绪进程有机会执行。这可以通过将当前进程从队列头部移动到队列尾部来实现。

  4. 谨慎的同步:在实现 RR 调度算法时,需要特别注意并发访问就绪队列的同步问题。由于多个进程可能同时访问就绪队列,因此必须确保对队列的访问是原子的,以避免竞态条件和数据一致性问题。

综上所述,实现 RR 调度算法涉及到利用定时器中断实现时间片的到期抢占,并在内核中进行就绪队列的管理和进程的调度。同时,需要特别关注并发访问的同步问题,以确保系统的稳定性和正确性。

Round-Robin Discussion

选择时间片的大小是实现 Round-Robin(RR)调度算法时的一个重要考虑因素。以下是关于选择时间片大小的一些考虑和实际选择:

时间片太大会怎样?

时间片无限大(无穷大)会怎样?

时间片太小会怎样?

实际选择的时间片大小

综上所述,选择合适的时间片大小需要平衡短作业的性能和长作业的吞吐量,并考虑系统的实际情况和资源利用率。通常情况下,时间片大小在 10 毫秒到 100 毫秒之间是一个合理的选择。

Handling Differences in Importance: Strict Priority Scheduling

image-20240325110108337

执行计划通常包括以下几个方面:

  1. 始终执行最高优先级的可运行作业
    • 系统会始终优先执行具有最高优先级的可运行作业,直至完成为止。这确保了高优先级任务能够及时得到执行,提高了系统对紧急任务的响应速度。
    • 如果有高优先级任务出现,且系统当前在执行低优先级任务,原则上系统会马上放弃低优先级任务的执行,转而去执行高优先级任务。
  2. 每个队列采用 RR 调度
    • 每个优先级队列内的作业通常采用 Round-Robin(RR)调度算法,以确保每个队列中的作业都有机会得到执行。每个队列的作业都会被分配一定的时间片,以平衡短作业的响应时间和长作业的吞吐量。

在执行计划中可能会遇到以下问题:

  1. 饥饿(Starvation)
    • 低优先级的作业可能因为高优先级作业的持续执行而得不到运行的机会。这会导致低优先级作业长时间等待,无法及时得到处理。
  2. 死锁(Deadlock):优先级反转
    • 当一个低优先级的任务持有一个高优先级任务所需的锁时,可能会发生优先级反转的死锁情况。通常情况下,第三个中间优先级的任务会阻止高优先级任务执行,从而导致死锁。
    • 这里可以通过优先级捐赠策略解决问题:当低优先级任务正在运行且持有锁,而突然出现的高优先级任务需要这个锁,此时终止该低优先级任务会发生死锁的问题,因此我们可以动态的将低优先级任务的优先级调至最高,待其执行完毕并释放锁后,再让新的高优先级任务执行。

解决这些问题的方法包括:

Scheduling Fairness

公平性是一个重要考虑因素:

如何实现公平性?

Shortest Job First & Shortest Remaining Time First

我们能否始终采用最佳的先来先服务(FCFS)呢?如果我们预先知道了每个作业期望的运行时间:

最短作业优先(SJF):

最短剩余时间优先(SRTF)-仅在进程不断到达期间有效,进程都到达后它会退化为SJF:

这些方法可以应用于整个程序或当前的CPU时间片

Discussion

SJF/SRTF 是最大限度减小平均响应时间的最佳方法

对比SRTF与FCFS

SRTF Further discussion

饥饿

一定程度上需要预测未来

实际上,我们无法确切知道作业需要多长时间

SRTF的优缺点

Predicting the Length of the Next CPU Burst

自适应:基于过去行为改变策略

例如:估计爆炸长度的SRTF

Lottery Scheduling(抽签调度)

另一种选择:抽奖调度

如何分配抽奖票?

相对于严格的优先级调度的优势:在负载变化时表现得更加优雅

Conclusion

循环轮询调度(round-robin):

最短作业优先(SJF)/最短剩余时间优先(SRTF):

多级反馈调度(下节课讲):

抽签调度: