操作系统——进程调度

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jay_zzs/article/details/113243173

目录

1. 基本概念

1.1 CPU-I/O执行周期

1.2 CPU调度程序(CPU scheduler)

1.3 进程状态模型

1.4 抢占调度

1.5 调度程序(dispatcher)

1.6 调度准则

2. 调度算法

2.1 先到先服务(FCFS)

2.2 最短作业优先调度(SJF)

2.3 优先级调度

2.4 轮转调度(RR)

2.5 多级队列调度

2.6 多级反馈队列调度

3 线程调度

参考资料:


进程调度目的在进程间切换CPU,最大化CPU利用率,通过操作系统的调度使得计算机资源分配和使用更加高效。

1. 基本概念

1.1 CPU-I/O执行周期

进程的属性:进程执行包括周期进行CPU执行I/O等待。据此可以将程序分为CPU密集型程序I/O密集型程序

CPU密集型程序一般只有少量长CPU执行;I/O密集型程序一般具有大量短CPU执行。

1.2 CPU调度程序(CPU scheduler

CPU空闲时,操作系统从就绪队列中选择一个进程来执行,进程选择采用短期调度程序(short-term scheduler)或CPU调度程序

调度程序分为:短期调度程序中期调度程序长期调度程序

  • 短期调度程序:从准备执行的进程中选择进程,并分配CPU,这里准备执行的进程理解为内存中就绪的进程。
  • 长期调度程序:从外部大容量存储设备(通常为磁盘)的缓冲池中选择进程,加载到内存。
  • 中期调度程序:将进程从内存(或从CPU竞争)中移出,从而降低多道程序程度(内存中的进程数量)。被调出的进程可被重新调入内存,并从中断处继续运行,这种方案称为交换(swap)。通过中期调度程序,进程可换入(swap in)和换出(swap out)。

1.3 进程状态模型

可以参考之前的博文——【操作系统——进程状态】。

其中七状态模型包含的情况比较全面,除了进程的创建、就绪、运行、等待、终止这五个状态,考虑在执行虚拟内存管理的操作系统中,可以将暂时不用的进程(处于就绪态和等待态的进程)换出(swap out)到外部存储设备(如硬盘)中,在适当的时间再将其换入(swap in)到内存中,此时引入了就绪挂起等待挂起状态。

1.4 抢占调度

需要CPU调度的4种情况

  1. 当一个进程从运行状态切换到等待状态(例如I/O请求,或wait()调用)

  2. 当一个进程从运行状态切换到就绪状态(例如当出现中断)

  3. 当一个进程从等待状态切换到就绪状态(例如I/O完成)

  4. 当一个进程终止

调度方案分为两种:(1)非抢占的(nonpreemptive)或协作的(cooperative)(2)抢占的(preemptive)非抢占调度下,一旦某个进程分配到CPU,该进程会一直使用CPU,直到它终止或切换到等待状态。抢占调度允许第二个进程抢占第一个进程的运行,这中间可能涉及进程共享数据的一致性问题,进程同步问题。

1.5 调度程序(dispatcher)

这个调度程序在英文原书中称为“dispatcher”,与上面说的CPU调度程序(CPU scheduler)不同,CPU scheduler负责进程的选择(调度),而dispatcher负责将CPU控制交给由CPU schedule(即短期调度程序)选择的进程CPU scheduler负责进程选择,dispatcher实现调度过程的进程切换细节,个人感觉二者属于上下游关系

dispatcher的主要功能如下:

  • 切换上下文;

  • 切换到用户模式;

  • 跳转到用户程序的合适位置,以便重新启动程序;

调度程序停止一个程序而启动另一个程序所需的时间称为调度延迟(dispatch latency)

1.6 调度准则

为了比较不同的CPU调度算法,采用一些比较准则来评价CPU调度算法的特性,具体的一些比较准则包括

  • CPU使用率
  • 吞吐量(throughput):一个时间单元内进程完成的数量;
  • 周转时间(turnaround time):进程从提交到进程完成的时间段;
  • 等待时间:进程在就绪队列种因等待所需的时间;
  • 响应时间:进程从提交请求到产生第一响应的时间。

进程调度的理想情况是:最大化CPU使用率和吞吐量,最小化周转时间、等待时间和响应时间。

2. 调度算法

2.1 先到先服务(FCFS)

先到先服务(First-Come First-Served,FCFS)调度算法。通过FIFO队列实现,当一个进程进入就绪队列中的时候,它的PCB会被链接到队列尾部;当CPU空闲时,它会分配给位于队列头部的进程,并且这个进程从队列中移去。

特点:

  • 平均等待时间往往很长;
  • 非抢占,可能导致一个进程占用CPU时间过长;
  • 会存在多个I/O进程在就绪队列中等待CPU密集型进程的完成(其他进程都等待一个大进程释放CPU),称为护航效果(convoy effect),导致CPU和设备的使用率降低。

2.2 最短作业优先调度(SJF)

最短作业优先(Shortest-Job-First,SJF)调度算法。将每个进程与其下次CPU执行长度关联起来,CPU空闲时会被赋给具有最短CPU执行时间(注意是下次CPU执行的时间最短而不是总的时间最短)的进程执行。另一种叫法是:最短下次CPU执行(shortest-next-CPU-burst)算法。

特点:

  • SJF算法可以证明是最优的,对于给定的一组进程,SJF算法的平均等待时间最短。
  • SJF算法困难在于如何确定下次CPU执行的长度。下次CPU执行通常预测为以前CPU执行的测量长度的指数平均(exponential average)。
  • SJF算法可以是抢占或非抢占的。

2.3 优先级调度

优先级调度(priority-scheduling)算法为每个进程关联一个优先级,具有最高优先级的进程会分到CPU;具有相同优先级的进程按照FCFS的顺序调度。SJF算法是一个简单的优先级算法,其优先级(p)为下次(预测的)CPU执行时间的导数。

特点:

  • 优先级算法可以是抢占的或非抢占的;
  • 主要问题是会导致无穷阻塞(indefinite blocking)饥饿(starvation)
  • 解决低优先级进程的无穷等待的方案之一:老化(aging),即逐渐增加在系统中等待时间很长的进程的优先级。

2.4 轮转调度(RR)

轮转(Round-Robin,RR)调度算法,类似FCFS调度,但是增加了抢占以切换进程。将一个较小的时间单元定义为时间量(time quantum)或时间片(time slice),将就绪队列作为循环队列,CPU调度整个就绪队列,为每个进程分配不超过一个是时间片的CPU。

特点:

  • RR算法的性能很大程度上取决于时间片的大小:时间片太小,频繁的进程上下文切换耗费大量资源;时间片太大,RR退化成FCFS。一般根据经验,80%的CPU执行应小于时间片。

2.5 多级队列调度

多级队列(multilevel queue)调度算法,将就绪队列分成多个单独的队列,根据进程属性(如内存大小、进程优先级、进程类型等),一个进程永久分到一个队列,每个队列有自己的调度算法。例如可有两个队列分别用于前台进程和后台进程,前台队列可采用RR算法调度,后台队列采用FCFS算法调度。

多级队列调度算法实例,有五个队列,优先级由高到低,分别为:(1)系统进程;(2)交互进程;(3)交互编辑进程;(4)批处理进程;(5)学生进程。其中每个队列与更低层队列相比具有绝对的优先,例如只有系统进程、交互进程和交互编辑进程队列都为空,批处理队列内的进程才能运行。如果一个批处理进程运行过程中有一个交互进程进入就绪队列,那么该批处理进程会被抢占。

另一种可能是,在队列之间划分时间片,每个队列具有一定比例的CPU时间,可用于调度队列内的进程。例如对于前台-后台队列例子,前台队列可有80%的CPU时间,用于进程之间的RR调度;后台队列可以有20%的CPU时间,用于按FCFS算法来调度进程。

2.6 多级反馈队列调度

多级反馈队列调度(multilevel feedback queue)调度算法允许进程在队列之间迁移,其特点在于:

  • 如果进程使用过多的CPU时间,其将会被放到更低的优先级队列;
  • I/O密集型和交互进程放在更高优先级队列上;
  • 在较低优先级队列中等待过长的进程会被移到更高优先级队列,以阻止饥饿的发生。

多级反馈队列调度程序可由下列参数定义:

  • 队列数量;
  • 每个队列的调度算法;
  • 用以确定何时升级到最高优先级队列的方法;
  • 用以确定何时降级到最低优先级队列的方法;
  • 用以确定进程在需要服务时将会进入那个队列的方法。

3 线程调度

线程可以分为用户级(user-level)线程内核级(kernel-level)线程在支持线程的操作系统上内核级线程(而不是进程)才是操作系统所调度的。这里理解为上述的进程调度算法,其实就CPU而言,并不严格区分该算法究竟是用于调度进程还是用于调度线程,而是用于调度基本的调度单元在支持线程的操作系统上,线程才是CPU调度的基本单元,此时上述调度算法此时用于线程调度。

关于用户级线程和内核级线程:用户级线程是由线程库管理的,内核并不知道。用户级线程最后运行在CPU上,映射到相应的内核级线程,这种映射不是直接的,可能采用轻量级进程(Light Weight Process,LWP),因此内核级线程和用户级线程的调度具体实现仍有所区别。

  • 进程竞争范围(Process-Contention Scope,PCS):对于实现多对一和多对多模型的系统线程库会调用用户级线程,以便在可用LWP上运行。线程调度到可用LWP上并不意味着线程真实运行在一个CPU上,而是需要系统调度内核线程到物理CPU)
  • 系统竞争范围(System-Contention Scope):为了决定哪个内核线程调度到同一个处理器上,内核采用SCS竞争CPU。采用一对一模型的系统如Windows、Linux和Solaris只采用SCS调度

参考资料:

[1] Silberschatz, A., Galvin, P. B., and Gagne, G. 操作系统概念(原书第9版) (郑扣根等译)[M]. 机械工业出版社, 2020.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,进程调度算法是操作系统中非常重要的一部分。常见的进程调度算法有先来先服务(FCFS)、短作业优先(SJF)、高响应比优先(HRRN)、时间片轮转(RR)等。下面是这些算法的 Python 实现: 1. 先来先服务(FCFS): ```python def FCFS(processes): waiting_time = 0 turn_around_time = 0 completion_time = 0 for process in processes: completion_time += process['burst_time'] turn_around_time += completion_time - process['arrival_time'] waiting_time += turn_around_time - process['burst_time'] return waiting_time / len(processes), turn_around_time / len(processes) ``` 2. 短作业优先(SJF): ```python def SJF(processes): processes = sorted(processes, key=lambda x: x['burst_time']) waiting_time = 0 turn_around_time = 0 completion_time = 0 for process in processes: completion_time += process['burst_time'] turn_around_time += completion_time - process['arrival_time'] waiting_time += turn_around_time - process['burst_time'] return waiting_time / len(processes), turn_around_time / len(processes) ``` 3. 高响应比优先(HRRN): ```python def HRRN(processes): waiting_time = 0 turn_around_time = 0 completion_time = 0 for i, process in enumerate(processes): if i == 0: completion_time = process['burst_time'] else: response_ratio_list = [] for j in range(i): response_ratio = (completion_time - processes[j]['arrival_time'] + processes[j]['burst_time']) / processes[j]['burst_time'] response_ratio_list.append(response_ratio) max_response_ratio_index = response_ratio_list.index(max(response_ratio_list)) selected_process = processes.pop(max_response_ratio_index) completion_time += selected_process['burst_time'] turn_around_time += completion_time - selected_process['arrival_time'] waiting_time += turn_around_time - selected_process['burst_time'] return waiting_time / len(processes), turn_around_time / len(processes) ``` 4. 时间片轮转(RR): ```python def RR(processes, time_slice): waiting_time = 0 turn_around_time = 0 completion_time = 0 while processes: for i in range(len(processes)): if processes[i]['burst_time'] > time_slice: completion_time += time_slice processes[i]['burst_time'] -= time_slice else: completion_time += processes[i]['burst_time'] turn_around_time += completion_time - processes[i]['arrival_time'] waiting_time += turn_around_time - processes[i]['burst_time'] processes.pop(i) break return waiting_time / len(processes), turn_around_time / len(processes) ``` 这里的 `processes` 是一个列表,其中每个元素是一个字典,表示一个进程的信息,如下所示: ```python processes = [ {'name': 'P1', 'arrival_time': 0, 'burst_time': 8}, {'name': 'P2', 'arrival_time': 1, 'burst_time': 4}, {'name': 'P3', 'arrival_time': 2, 'burst_time': 9}, ... ] ``` 在这个列表中,每个进程有一个名称、到达时间和执行时间。你可以根据自己的需要修改这些信息,来测试这些进程调度算法的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值