《Tsinghua os mooc》第15~16讲 处理机调度
第十五讲 处理机调度
-
进程调度时机
- 非抢占系统中,当前进程主动放弃CPU时发生调度,分为两种情况:
- 进程从运行状态切换到等待状态
- 进程被终结了
- 可抢占系统中,中断请求被服务例程响应完成时发生调度,也分为两种情况:
- 进程时间片用完
- 有更高优先级的进程从等待切换到就绪
- 非抢占系统中,当前进程主动放弃CPU时发生调度,分为两种情况:
-
比较调度算法的准则
- CPU使用率:CPU处于忙状态的时间百分比
- 吞吐量:单位时间内完成的进程数量
- 周转时间:进程从初始化到结束(包括等待)的总时间
- 等待时间:进程在就绪队列中的总时间
- 响应时间:从提交请求到产生响应所花费的总时间
-
处理机调度策略的吞吐量目标
- 增加吞吐量:减少开销(操作系统开销,上下文切换)、系统资源的高效利用(CPU,I/O设备)
- 减少等待时间:减少每个进程的等待时间
- 操作系统需要保证吞吐量不受用户交互的影响:操作系统必须不时进行调度,即使存在许多交互任务
-
先来先服务算法(First Come First Served, FCFS)
- 策略:依据进程进入就绪状态的先后顺序排列,进程进入等待或结束状态时,就绪队列中的下一个进程占用CPU。
- 优点:简单
- 缺点:
- 平均等待时间波动较大,短进程可能排在长进程后面
- I/O资源和CPU资源的利用率较低,CPU密集型进程会导致I/O设备闲置时,I/O密集型进程也等待
-
短进程优先算法(SPN)
- 策略:选择就绪队列中执行时间最短进程占用CPU进入运行状态,就绪队列按预期的执行时间来排序
- 优点:短进程优先算法具有最优平均周转时间
- 缺点:
- 可能导致饥饿,连续的短进程流会使长进程无法获得CPU资源
- 需要预知未来,方法有询问用户、用历史的执行时间来预估未来的执行时间
-
最高响应比优先算法(HRRN)
- 策略:选择就绪队列中响应比R值最高的进程,R = (w + s)/s,w是等待时间,s是执行时间
- 优点:在短进程优先算法的基础上改进,不可抢占,关注进程的等待时间,防止无限期推迟
-
时间片轮转算法(RR, Round-Robin)
- 时间片:分配处理机资源的基本时间单元
- 策略:每隔(n – 1)个时间片进程执行一个时间片q,时间片结束时,按FCFS算法切换到下一个就绪进程
- RR算法开销:额外的上下文切换(时钟中断时强行把正在执行的进程结束掉,切换到另一个进程)
- 时间片太大:等待时间过长,极限情况退化成FCFS
- 时间片太小:反应迅速,但产生大量上下文切换,大量上下文切换开销影响到系统吞吐量
- 时间片长度选择目标:选择一个合适的时间片长度,经验规则是维持上下文切换开销处于1%以内,时间片经验值为10毫秒
- 优点:交互性较好
- 缺点:等待时间较长
-
多级队列调度算法(MQ)
- 策略:多种算法的集成。就绪队列被划分成多个独立的子队列,每个队列拥有自己的调度策略。比如将队列分为前台(交互)、后台(批处理),采取策略分别是前台–RR、后台–FCFS。
- 队列间的调度
- 固定优先级:先处理前台,然后处理后台,可能导致饥饿
- 时间片轮转:每个队列都得到一个确定的能够调度其进程的CPU总时间,如80%CPU时间用于前台,20%CPU时间用于后台
-
多级反馈队列算法(MLFQ)
- 策略:进程可在不同队列间移动的多级队列算法
- 特征
- 时间片大小随优先级级别增加而增加
- 如进程在当前的时间片没有完成,则降到下一个优先级
- CPU密集型进程的优先级下降很快
- I/O密集型进程停留在高优先级
-
公平共享调度(FSS, Fair Share Scheduling)
- 策略:FSS控制用户对系统资源的访问
- 一些用户组比其他用户组更重要
- 保证不重要的组无法垄断资源
- 未使用的资源按比例分配
- 没有达到资源使用率目标的组获得更高的优先级
-
优先级反置
- 现象描述:操作系统中出现高优先级进程长时间等待低优先级进程所占用资源的现象
- 出现场景:基于优先级的可抢占调度算法存在优先级反置
- 解决方案1:优先级继承。占用资源的低优先级进程继承申请资源的高优先级进程的优先级。注意,只在占有资源的低优先级进程被阻塞时,才提高占有资源进程的优先级。
- 解决方案2:优先级天花板协议(priority ceiling protocol)。占用资源进程的优先级和所有可能申请该资源的进程的最高优先级相同。不管是否发生等待,都提升占用资源进程的优先级。优先级高于系统中所有被锁定的资源的优先级上限,任务执行临界区时就不会被阻塞。
第十六讲 实验六 调度器
-
lab6重新设计调度框架
- 初始化:实现调度算法的调度类 -> 绑定调度类 -> 设定调度点
- 调度过程:触发调度事件 -> 调整调度参数、调用调度算法 -> 选择新进程(若没有就绪进程,则运行idle线程),进程切换
-
调度点:触发做调度相关的工作
- proc.c:do_exit:用户线程执行结束,主动放弃CPU
- proc.c:do_wait:用户线程等待子进程结束,主动放弃CPU
- proc.c:init_main:1.Initproc内核线程等待所有用户进程结束;2.所有用户进程结束后,回收系统资源
- proc.c::cpu_idle:idleproc内核线程等待处于就绪态的进程或线程,如果有选取一个并切换进程
- sync.h::lock:进程如果无法得到锁,则主动放弃CPU
- Trap.c::trap:修改当前进程时间片,若时间片用完,则设置need_resched为1,让当前进程放弃CPU(与调度算法相关)
-
问题:调度算法如何知道进程的事件使用情况?
答案:让调度算法能够感知到时钟中断的产生。 -
进入/离开就绪队列:抽象数据结构,可以不是队列。可根据调度算法的需求采用各种具体数据结构。
-
调度算法支撑框架
- 触发:trigger scheduling -> proc_tick
- 入队:enqueue
- 选取:pick up -> proc_next
- 出队:dequeue
- 切换:process switch -> switch_to
struct sched_class {
const char *name;
void (*init)(struct run_queue *rq);
void (*enqueue)(struct run_queue *rq, struct proc_struct *proc);
void (*dequeue)(struct run_queue *rq, struct proc_struct *proc);
struct proc_struct *(*pick_next)(struct run_queue *rq);
void (*proc_tick)(struct run_queue *rq, struct proc_struct *proc);
};
-
步进值pass与优先级priority的关系:pass=BIG_VALUE/lab6_priority
-
如何避免stride溢出?
- STRIDE_MAX – STRIDE_MIN <=PASS_MAX
- stride, pass 是无符号整数
- 比较时用有符号整数表示(Proc.A.stride –Proc.B.stride)