CPU调度策略
任务调度策略的三个基本准则
- 任务周转时间:从新建到完成的时间
- 任务响应时间:从提交请求到首次响应的时间(前台任务关心)
- 系统吞吐量:一段时间内系统能完成的任务数
调度算法
先来先服务
最短作业优先调度:不可抢占,平均周转时间短(作业运行时间只能近似给出)
最短剩余时间有限:最短作业优先的可抢占版本
时间片轮转调度:保证响应时间
时间片设得太短会导致过多的进程切换,降低了CPU效率;设得太长会引起对短作业的交互请求的响应时间变长
多级反馈队列调度:动态调整任务类型(近期多IO可能为前台任务,无IO时间片结束未完成可能为后台大任务)
运行流程
- 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
- 新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片。 若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回最下级队列队尾
- 只有第k级队列为空时,才会为k+1级队头的进程分配时间片
调度算法比较
其他
- IO占比越大,任务优先级越高
进程同步与互斥
实现临界区互斥的基本方法
软件实现
Peterson算法:访问临界区前判断其他进程是否要用,要用则循环等待;等其他进程使用完后访问临界区
硬件实现
- 开关中断:只适用于单处理机,可以使得一个处理机内任务不中断。如果多处理机要实现互斥需要总线支持
- TestAndSet
1 |
|
信号量
记录型信号量支持让权等待(while判断循环的都不是让权等待)
退出临界区的进程负责唤醒阻塞态进程(区别于while判断循环的自发进入临界区)
1 | struct semaphore |
1 | void P(semaphore s) |
生产者/消费者模型
1 | // use semaphore |
读者/写者模型
读者优先
读写公平
哲学家进餐问题
各哲学家互斥得拿筷子,即同一时间至多有一个哲学家拿筷子阻塞
死锁
死锁的四个必要条件
- 互斥:资源不能被共享,一个资源每次只能被一个进程使用
- 不可剥夺:进程已获得的资源,在未使用完之前,不能强行剥夺
- 请求与保持:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 循环等待:若干进程之间形成一种头尾相接的循环性资源等待关系
死锁预防(不会发生死锁)
破坏“请求与保持”:一次性申请进程所需的所有资源
破坏“循环等待”:资源按顺序申请(其实达不到,没法预测程序走的分支)
缺点:
- 需要预先计算程序要请求的资源
- 可能很久以后才使用的资源早早地预留下来,造成资源的浪费
死锁避免(拒绝某些资源请求)
每次申请资源都要判断是否出现死锁的危险,如果有危险就拒绝这次请求
通过银行家算法计算安全序列,充分性算法,完全避免死锁
算法优先分配给能满足进程所需最大资源量的进程,一次分配所有所需要的所有资源
缺点:
- 每次资源请求发生就要计算,且时间复杂度不小(时间复杂度O(mn^2),m为资源种类,n为进程数)
- 需要已知进程执行完成所需的资源总数
银行家算法(‼️)
- 判断请求是否小于所需资源
- 判断请求是否小于当前系统资源量
- 尝试分配,判断能否找出安全序列
- 若能找到则分配,若不能找到则不分配
求安全序列
最大资源组A,已分配组B,还需资源组C(C=A-B)
系统资源组P
- 查看还需 资源A 小于等于 系统资源P 的进程
- 一次分配后,将已分配的资源回收,更新系统P
- 返回1,若所有进程都能分配,则存在安全序列(不唯一)
备注:
- 存在安全序列 -》无死锁进程
- 不存在安全序列不一定发生死锁(依赖于请求资源的序列)
不发生死锁的最小资源量
每个所需资源都-1后累加,再加一(每个所需资源都-1为请求与保持的最坏情况,+1即可确保分配不发生死锁)
死锁检测/恢复(排查因资源导致的阻塞进程)
检测发生死锁的进程(资源未被使用,进程长时间未调度等),恢复进程并重新分配资源(改进的银行家算法)
改进的银行家算法分配每次进程请求的资源,而不是分配所需的所有资源,因为有事进程对于资源使用后就会释放,这样系统有更多余量
缺点:
- 回滚的处理问题
死锁忽略(大部分PC机操作系统)
不进行死锁处理