调度
调度🐑
有两个或多个进程处于就绪状态,如果只有一个CPU,CPU选择下一个要运行的进程。在操作系统中,完成选择工作的一部分称为调度程序(scheduler),该程序使用的算法称为调度算法(scheduling algorithm)
一.调度简介🐘
不同时代的调度复杂度不同
为了选取正确的进程运行,调度程序还要考虑CPU的利用率,因为进程切换的代价是比较高的。
1.进程切换过程
①首先用户态必须切换到内核态
②然后要保存当前进程的状态,包括在进程表中存储寄存器值以便以后重新装载
③在许多系统中,内存映像(例如,页表内的内存访问位)也必须保存
④接着,通过运行调度算法选定一个新进程
⑤然后将形成的内存映像重新转入MMU,
⑥最后新进程开始运行
除此之外,进程切换还要使整个内存高速缓存失效,强迫缓存从内存中动态重新转入两次(进入内核一次,离开内核一次)
2.进程行为
几乎所有进程的(磁盘或网络)I/O请求和计算都是交替突发的
a)CPU密集型(compute-bound)进程:花费大多数时间在计算上
b)I/O密集型(I/O-bound)进程:花费了大多数时间在等待I/O上
无论如何,它们都花费同样的时间提出硬件请求读取磁盘块,随着CPU变得越来越快,更多的进程倾向I/O密集型
2.何时调度
①在创建一个新进程后,需要决定是运行父进程还是子进程,而两者都处于就绪状态,所以这是一种正常的调度策略,可以任意决定
②在第一个进程退出时必须做出调度策略。一个进程不再运行,所以要选另一个就绪进程,如果没有,就运行一个系统提供的空闲进程
③当一个进程阻塞在I/O和信号量上或其他原因阻塞时,必须选择另一个进程运行
④在一个I/O中断发生时,必须做出调度策略
根据如何处理时钟中断,可把调度算法分为两类:
(1)非抢占式调度算法:挑选一个进程,然后让该进程运行直至被阻塞(阻塞在I/O上或等待另一个进程),或者直到进程自动释放CPU
(2)抢占式调度算法:挑选一个进程,并且让该进程运行某个固定时段的最大值。如果在该时段结束时,该进程仍在运行,它就被挂起,而调度程序挑选另一个进程运行(如果存在一个就绪程序)。进行抢占式调度处理,需要在时间间隔的末端发生时钟中断,以便把CPU控制返回给调度程序。如果没有可用的时钟,那么抢占式调度就是唯一的选择
3.调度算法分类
①系统可划分三种环境
(1)批处理:用来处理薪水册、存货清单、账目收入和其他的周期性的作业,因此是非抢占式算法
(2)交互式:为了避免一个进程霸占CPU拒绝为其他进程服务,抢占式是必须的
(3)实时:不需要抢占,因为进程了解它们可能会长时间得不到运行,所以通常很快地完成各自的工作并阻塞。它与交互式系统的区别是,它只运行那些推进现有应用的程序,而交互式系统是通用的
4.调度算法的目标
①不同环境中调度算法的一些目标
②运行大量批作业---掌握其系统工作状态的三个指标
(1)吞吐量(through):是系统每小时完成的作业数量
(2)周转时间(turnaround time):是指从一个批处理提交时刻开始直到该作业完成时刻为止的统计平均时间
(3)CPU利用率:常常是用于对批处理系统的度量,但它并不是一个好的度量参数
交互式系统的指标:最小响应时间,即从发出命令到得到响应之间的时间
实时系统的指标:或多或少必须满足截止时间
二.批处理系统中的调度🐼
1.先来先服务(first-come first-served)算法
非抢占式的,进程按照它们请求CPU的顺序使用CPU,排队(就绪队列),阻塞变就绪的进程排末尾
2.最短优先作业(shortest job first)算法
非抢占式的,适用于运行时间可以预知的批处理调度算法,只有在所有的作业都可同时运行的情形下,最短优先算法才是最优化的
3.最短剩余时间优先(shortest remaining time next)
最短作业优先的抢占式版本,调度程序总是选择剩余运行时间最短的那个进程运行(有关运行时间必须提前掌握),当一个新的作业到达时,其整个时间同当前进程的剩余时间作比较,若新的进程需更少时间,当前进程就被挂起,而运行新的进程。这样可使新的短作业获得良好的服务
三.交互式系统中的调度🐍
1.轮转调度(round robin)
每个进程被分配一个时间段,称为时间片(quantum),即允许该线程在该时间段中运行。如果时间片结束时该进程还在运行,则将剥夺CPU并分配给另一个进程,若该进程在时间片结束前阻塞或结束,则CPU立即进行切换
时间片的长度很重要,进程的切换(process switch),也称上下文切换(context switch)**需要一定的时间进行管理事务进行--保存和转入寄存器值及内存映像、更新各种表格和列表、清除和重新调入内存高速缓存等
它不能设置太短,过多的进程切换,会耗费太多切换时间,降低CPU工作效率;不能设置太长,防止对短的交互请求的响应时间过长的情况出现,20~50ms比较合理
2.优先级调度
每个进程被赋予一个优先级,允许优先级最高的可运行进程先运行
①为防止高优先级无休止地运行下去,调度程序可能在每个时钟滴答(即每个时钟中断)降低当前进程的优先级,结果是当前进程可能低于次高优先级进程,则进行进程切换
②另一个方法是给每个进程赋予一个允许运行的最大时间片,当用完这个时间片时,次高优先级的进程便获得运行机会
③将一组进程按优先级分类,并且在各类之间采用了优先级调度,各类进程的内部采用轮转调度
3.多级队列
最高优先级类的进程运行2个时间片,再次一级运行4个时间片,以此类推,当一个仅次于用完分配的时间片后,它被移到下一类
4.最短进程优先
交互进程遵循模式:等待命令、执行命令、等待命令、执行命令,如此不断反复。如果将每一条命令的执行看作是一个独立的“作业”,则我们可以通过首先运行最短的作业来使响应时间最短
5.保证调度
在一个有n个进程运行的当用户系统中,若所有的进程都等价,则每个进程获得1/n的CPU时间。
系统必须跟各个进程自创建以来已使用了多少CPU时间,然后它计算各个进程应获得的CPU时间,自创建以来的时间除以n
6.彩票调度(lottery scheduling)
为进程提供各种系统资源(如CPU时间)的彩票,一旦需要做出一项调度决策时,就随机抽出一张彩票,拥有该彩票的进程获得该资源
7.公平分享调度
在这个模式里,每个用户分配到CPU时间的一部分,而调度程序以一种强制得方式选择进程
四.实时系统中的调度🐦
时间起主导作用的系统
把程序划分为一组进程而实现的,其中每个进程的行为是可预测和提前掌握的
1.硬实时
必须满足绝对的截止时间
2.软实时
虽然不希望偶尔措施截止时间,但可以容忍
3.按响应方式分类
(1)周期性(以规则的时间间隔发生)事件
(2)非周期性(发生时间不可预知)事件
五.策略和机制🐤
还有一种情况:一个进程有许多子进程并在其控制下运行,每个子进程处理不同的请求,或每一个子进程实现不同的功能,所带来的问题是,以上列出的算法中没有一个从用户进程接收调度决策信息,这就导致了调度程序很少能够做出最优的选择
解决问题:
将调度机制(scheduling)与调度策略(scheduling policy)分离
将调度算法以某种形式参数化,而参数可以由用户进程填写
六.线程调度🐥
1.用户级线程
把整个线程实现部分放在用户空间中,内核对线程一无所知,内核看到的就是一个单线程进程。
优点:
①可以在不支持线程的操作系统中实现。
②创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多, 因为保存线程状态的过程和调用程序都只是本地过程
③允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程的区别
④线程能够利用的表空间和堆栈空间比内核级线程多
⑤不需要陷阱,不需要上下文切换,也不需要对内存高速缓存进行刷新,使得线程调用非常快捷
⑥线程的调度不需要内核直接参与,控制简单。
缺点:
①线程发生I/O或页面故障引起的阻塞时,如果调用阻塞系统调用则内核由于不知道有多线程的存在,而会阻塞整个进程从而阻塞所有线程, 因此同一进程中只能同时有一个线程在运行
②页面失效也会产生类似的问题。
③一个单独的进程内部,没有时钟中断,所以不可能用轮转调度的方式调度线程
④资源调度按照进程进行,多个处理机下,同一个进程中的线程只能在同一个处理机下分时复用
2.内核级线程
内核线程建立和销毁都是由操作系统负责、通过系统调用完成的。在内核的支持下运行,无论是用户进程的线程,或者是系统进程的线程,他们的创建、撤销、切换都是依靠内核实现的。
用户级线程切换需要少量的机器指令,而内核级线程需要完整的上下文切换,修改内存映像,使高速缓存失效,这导致了若干数量级的延迟。而且一旦线程阻塞I/O上就不需要像在用户线程中那样整个进程挂起
优点:
①多处理器系统中,内核能够并行执行同一进程内的多个线程
②如果进程中的一个线程被阻塞,能够切换同一进程内的其他线程继续执行(用户级线程的一个缺点)
③所有能够阻塞线程的调用都以系统调用的形式实现,代价可观
④当一个线程阻塞时,内核根据选择可以运行另一个进程的线程,而用户空间实现的线程中,运行时系统始终运行自己进程中的线程
⑤信号是发给进程而不是线程的,当一个信号到达时,应该由哪一个线程处理它?线程可以“注册”它们感兴趣的信号
3.从进程A的线程切换到进程B的一个线程,其代价高于运行进程A的第二个线程
4.另一个重要因素是用户线程可以使用专为应用程序定制的线程调度程序
5.用户级别线程和内核级线程的区别:
①内核支持线程是OS内核可感知的,而用户级线程是OS内核不可感知的。
②用户级线程的创建、撤消和调度不需要OS内核的支持,是在语言(如Java)这一级处理的;而内核支持线程的创建、撤消和调度都需OS内核提供支持,而且与进程的创建、撤消和调度大体是相同的。
③用户级线程执行系统调用指令时将导致其所属进程被中断,而内核支持线程执行系统调用指令时,只导致该线程被中断。
④在只有用户级线程的系统内,CPU调度还是以进程为单位,处于运行状态的进程中的多个线程,由用户程序控制线程的轮换运行;在有内核支持线程的系统内,CPU调度则以线程为单位,由OS的线程调度程序负责线程的调度。
⑤用户级线程的程序实体是运行在用户态下的程序,而内核支持线程的程序实体则是可以运行在任何状态下的程序。
参考书籍《现代操作系统》