上一篇介绍了操作系统线程的概念,接下来开始介绍具体是如何调度线程的。
进程调度实际上是调度进程中的线程,所以说线程是 CPU 调度的基本单位。
进程调度又称 CPU 调度,指的是决定哪个线程被优先运行和运行多久。
操作系统创建一个进程后,进程的入口程序被分配到了一个主线程执行,这样看上去操作系统是在调度进程,其实是调度进程中的线程。
当进程从运行状态变化到其他状态,或者从其他状态变化到运行状态时,就会触发一次调度。
根据如何处理时钟中断 ,把调度算法分为两类:
原则一:如果运行的程序,发生了 I/O 事件的请求,那 CPU 使用率必然会很低,因为此时进程在阻塞等待硬盘的数据返回。这样的过程,势必会造成 CPU 突然的空闲。所以,为了提高 CPU 利用率,在这种发送 I/O 事件致使 CPU 空闲的情况下,调度程序需要从就绪队列中选择一个进程来运行。
原则二:有的程序执行某个任务花费的时间会比较长,如果这个程序一直占用着 CPU,会造成系统吞吐量(CPU 在单位时间内完成的进程数量)的降低。所以,要提高系统的吞吐率,调度程序要权衡长任务和短任务进程的运行完成数量。
原则三:从进程开始到结束的过程中,实际上是包含两个时间,分别是进程运行时间和进程等待时间,这两个时间总和就称为周转时间。进程的周转时间越小越好,如果进程的等待时间很长而运行时间很短,那周转时间就很长,这不是我们所期望的,调度程序应该避免这种情况发生。
原则四:处于就绪队列的进程,也不能等太久,当然希望这个等待的时间越短越好,这样可以使得进程更快的在 CPU 中执行。所以,就绪队列中进程的等待时间也是调度程序所需要考虑的原则。
原则五:对于鼠标、键盘这种交互式比较强的应用,我们当然希望它的响应时间越快越好,否则就会影响用户体验了。所以,对于交互式比较强的应用,响应时间也是调度程序需要考虑的原则。
针对上面的五种调度原则,总结成如下:
调度算法可以分为静态优先级调度和动态优先级调度。
按照不同的操作系统环境,可以分为以下三种调度算法:批处理、实时、交互式。
先来先服务,First Come First Serve, FCFS,每次从就绪队列选择最先进入队列的进程,然后一直运行,直到进程退出或被阻塞,才会继续从队列中选择第一个进程接着运行。
最短作业优先,Shortest Job First, SJF,优先选择运行时间最短的进程来运行。
最短剩余时间优先,Shortest Remaining Time Next,SRTN,优先选择剩余运行时间最短的进程运行。
实时系统是一种时间起着主导作用的系统,系统必须在一个确定的时间范围内恰当地做出反应。例如自动驾驶系统等。
实时任务可以根据是否严格满足时间要求分为硬实时任务和软实时任务,也可以根据是否具有周期性规律分为随机任务和周期性任务。
比率单调调度算法,Rate Monotonic Scheduling,RMS,面向周期性实时任务,将任务的周期作为调度参数,其发生频度越高,则调度级别越高。是最佳的静态优先级调度算法。
最早截止时间优先,Earliest Deadline First,EDF,根据任务的截止时间来确定任务的优先级。截止时间越早,其优先级越高。是最佳的动态优先级调度算法。
高响应比优先调度算法,Highest Response Ratio Next, HRRN,每次进行进程调度时,先计算响应比优先级,然后把优先级最高的进程投入运行。响应比优先级=(等待时间+要求服务时间)/要求服务时间。
由于要求服务时间是不可预知的,所以高响应比优先调度算法在现实中是实现不了的。
时间片轮转调度算法,Round Robin, RR,每个进程被分配一个时间段,称为时间片(Quantum),即允许该进程在该时间段中运行。
时间片轮转算法是最简单、公平、常用的算法,一般来说,时间片设为 20ms~50ms 是一个比较合理的折中值。
最高优先级调度算法,Highest Priority First,HPF,从就绪队列中选择最高优先级的进程进行运行。
进程的优先级可以分为,静态优先级和动态优先级:
多级反馈队列调度算法,Multilevel Feedback Queue。
公平共享调度算法,Fair Share Scheduling,FSS,在用户级别实现资源的公平共享,而不是在进程级别。
Priority Inversion,高优先级进程因需要的资源被占用而阻塞,反而在低优先级进程后执行的现象。
当一个进程创建后,会加入到就绪队列当中等待调度,CPU 分配给进程的时间片是有限的,每隔一段时间都会触发一次时钟中断,去查看当前运行进程的时间是否充足,当到达一定时间后,就会发生上下文切换,选择另一个进程运行。调度指的就是选择进程运行。
不同的操作系统会根据自身的特性,设计不同的调度算法。