处理机调度的层次和调度算法的目标
调度的实质是一种资源分配,处理机调度是对处理机资源进行分配
- 处理机调度的层次
- 高级调度(作业调度):将外存上处于后备队列的作业调入内存
- 中级调度(内存调度):把暂时不能运行的进程调至外存等待
实际上就是存储器管理中的对换功能 - 低级调度(进程调度):决定就绪队列中哪个进程获得处理机
进程调度的运行频率最高
- 处理机调度算法的目标
- 资源利用率
- 公平性
- 平衡性
- 策略强制执行
- 批处理系统的目标
- 平均周转时间短
周转时间:作业被提交给系统开始,到作业完成为止的这段时间间隔- 作业在外存后备队列上等待调度的时间
- 进程在就绪队列等待进程调度的时间
- 进程在CPU上执行的时间
- 进程等待I/O操作完成的时间
- 系统吞吐量高
- 处理机利用率高
- 平均周转时间短
- 分时系统的目标
- 响应时间快
- 均衡性
- 实时系统的目标
- 截止时间的保证
- 可预测性
作业与进程的基本概念
- 批处理系统中的作业
- 作业和作业步
- 作业
作业是用户提交给系统的一项相对独立的工作,它不仅包含了通常的程序和数据,而且还应配有一份作业说明书,系统根据该说明书来对程序的运行进行控制 - 作业步
在作业运行期间,每个作业都必须经过若干个相对独立,又相互关联的顺序加工步骤才能得到结果。其中的每一个加工步骤称为一个作业步。
- 作业
- 作业控制块(JCB)
- 定义
作业控制块是作业在系统中存在的标志,其中保存了系统对作业进行管理和调度所需的全部信息 - 内容
JCB中包含的内容有:- 作业标识
- 用户名称
- 用户账号
- 作业类型(CPU 繁忙型I/0 繁忙型、批量型、终端型)
- 作业状态
- 调度信息(优先级、作业运行时间)
- 资源需求(预计运行时 间、要求内存大小等)
- 资源使用情况
- 定义
- 进程调度的任务和方式
- 两个决定
- 每一次进行作业调度时,应当从后备队列中选取多少作业调入内存,取决于多道程序度,即允许多少个作业同时在内存中运行
- 应选择后备队列中的哪些作业调入内存,取决于所采用的调度算法
- 进程调度的任务
- 保存处理机的现场信息
- 按某种算法选取进程
- 把处理器分配给进程
- 进程调度方式
- 非抢占方式
- 抢占方式
“抢占”必须遵循一定的原则,主要原则有:- 优先权原则
- 短进程优先原则
- 时间片原则。
- 不能进行进程调度的情况
- 在处理中断的过程中
- 进程在操作系统内核程序临界区中
- 需要完全屏蔽中断的原子操作过程中
- 两个决定
- 调度的基本准则
-
CPU 利用率
其中计算公式为:
C P U 的利用率 = C P U 有效工作时间 C P U 有效工作时间 + C P U 空闲等待时间 CPU的利用率=\frac{CPU有效工作时间}{CPU有效工作时间+CPU空闲等待时间} CPU的利用率=CPU有效工作时间+CPU空闲等待时间CPU有效工作时间 -
系统吞吐量
-
周转时间
需掌握以下公式:
周转时间 = 作业完成时间 − 作业提交时间 周转时间=作业完成时间-作业提交时间 周转时间=作业完成时间−作业提交时间
平均周转时间 = ( 作业 1 的周转时间 + ⋯ + 作业 n 的周转时间 ) 平均周转时间=(作业1的周转时间+\dots+作业n的周转时间) 平均周转时间=(作业1的周转时间+⋯+作业n的周转时间)
带权周转时间 = 作业周转时间 作业实际运行时间 带权周转时间=\frac{作业周转时间}{作业实际运行时间} 带权周转时间=作业实际运行时间作业周转时间 -
等待时间
-
响应时间
-
- 作业和作业步
典型调度算法
- 先来先服务(FCFS)调度算法
- FCFS 算法既可用于作业调度,也可用于进程调度
- 每次选择最早进入队列的作业(或进程)调入内存(或分配处理机)
- 属于不可剥夺算法
- 有利于CPU繁忙型作业,不利于I/O繁忙型作业;有利于长作业,不利于短作业
- 短作业优先(SJF)调度算法
- SJF算法既可用于作业调度,也可用于进程调度
- 每次选择运行时间最短的作业(或进程)调入内存(或分配处理机)
- 对长作业不利,且未考虑作业的紧迫程度,必须预知作业的运行时间
- SJF算法的平均等待时间、平均周转时间最少
- 优先级调度算法
- 既可用于作业调度,也可用于进程调度
- 每次选择优先级最高的作业(或进程)调入内存(或分配处理机)
- 根据更高优先级进程是否可以抢占正在执行的进程
分类为:- 抢占式优先级调度算法
- 非抢占式优先级调度算法
- 根据进程的优先级是否可以改变
将进程的优先级分类为:- 静态优先级
- 动态优先级
- 高响应比优先调度算法(HRRN)
- 该算法主要用于作业调度
- 既考虑了作业的等待时间,又考虑了作业运行时间
- 响应比
R
p
R_{p}
Rp的计算公式为
R p = 等待时间 + 要求服务时间 要求服务时间 = 响应时间 要求服务时间 R_{p}=\frac{等待时间+要求服务时间}{要求服务时间}=\frac{响应时间}{要求服务时间} Rp=要求服务时间等待时间+要求服务时间=要求服务时间响应时间- 如果作业的等待时间相同,则要求服务的时间愈短,其优先权愈高,有利于短作业
- 当要求服务的时间相同时,作业的优先权又决定于其等待时间,类似于FCFS算法
- 长作业的优先级可以随等待时间的增加而提高,当其等待时间足够长时,也可获得处理机,避免“饥饿”
- 时间片轮转调度算法
- 主要适用于分时系统
- 每次选择就绪队列中的第一个进程,但是只能运行一个时间片大小
- 时间片长短的选择参考因素:
- 系统的响应时间
- 就绪队列中的进程数目
- 系统的处理能力
- 多级反馈队列调度算法
- 调度机制
- 设置多个就绪队列,并为每个队列赋予不同的优先级。第一队列优先级最高,其余队列优先级依次降低
- 各个队列中进程执行时间片大小不同。优先级越高的队列中进程运行的时间片越小
- 除第n队列外,每个队列都采用FCFS算法,第n队列中按RR方式运行
- 调度算法的优势
- 终端型用户:短作业优先
- 短批处理作业用户:周转时间短
- 长批处理作业用户:经过前面队列的部分执行,不会出现“饥饿”
- 调度机制
信号量
- 信号量机制
- 整型信号量
- 定义
把整型信号量定义为一个用于表示资源数目的整型量S - 描述
通过两个标准的原子操作wait(S)和signal(S)来访问S,两个操作一直被分别称为P、V操作。wait和signa!操作可描述如下wait(S) { while (S <= 0) S--; } signal(S) { S++; }
- 定义
- 记录型信号量
- 定义
记录型信号量机制采用了记录型的数据结构,是一种不存在“忙等”现象的进程同步机制 - 描述
- 定义
- 整型信号量
typedef struct
{
int value; //代表资源数目的整型变量
struct process_control_block *list; //一个链接所有等待进程的进程链表指针
}semaphore;
wait(S)和signal(S)操作可描述如下:
wait (semaphore *S)
{
S->value--;
if (S->value < 0)
block(S->list);
}
signal(semaphore *s)
{
S->value++;
if (S->value <= 0)
wakeup(S->list);
}
- 经典同步问题-生产者·消费者问题
- 问题描述:
一组生产者进程和一组消费者进程共享一个初始为空,大小为n个单元的缓冲区。
只有当缓冲区没满时,生产者才可以把消息放入缓冲区,否则必须等待;
只有当缓冲区不空时, 消费者才可以从中取出消息,否则必须等待。
由于缓冲区是临界资源,只允许一个生产者放入消息或者一个消费者从中取出消息,不允许同时访问缓冲区。 - 信号量设置:
定义信号量mutex为互斥信号量,初值为1,用于表示互斥访问缓冲区;
信号量empty用于表示当前缓冲区中可用空间大小,初值为n;
信号量full用于表示当前缓冲区中已用空间大小,初值为0 - 程序描述
- 问题描述:
semaphore mutex = 1; //临界区互斥信号量
semaphore empty = n; //空闲缓冲区
semaphore full = 0; //缓冲区初始化为空
producer() //生产者进程
{
while (1)
{
//生产数据
wait(empty); //获取空缓冲区单元
wait(mutex); //进入临界区
//将数据放入缓冲区
i = (i + 1) % n;
signal(mutex); //离开临界区,释放互斥信号量
signal(full); //满缓冲区数+1
}
}
consumer() //消费者进程
{
while (1)
{
wait(full); //获取满缓冲区单元
wait(mutex); //进入临界区
//从缓冲区中取出数据
j = (j + 1) % n;
signal(mutex); //离开临界区,释放互斥信号量
signal(empty); //空缓冲区数+1
//消费数据
}
}
死锁
- 死锁的定义、必要条件和处理方法
- 死锁的定义
死锁是指多个进程因竞争资源而造成的一种相互等待,若无外力作用,这些进程都将无法继续运行 - 产生死锁的原因
- 竞争不可抢占性资源
- 竞争可消耗资源
- 进程推进顺序不当
- 产生死锁的必要条件
产生死锁必须同时具备下面四个必要条件,只要其中一个条件不成立,死锁就不会发生- 互斥条件:进程对所分配到资源进行排他性使用
- 请求和保持条件:请求进程被阻塞,但对自己已获得的资源保持不放
- 不可抢占条件:进程已获得的资源在未使用完之前不能被抢占
- 循环等待条件:发生死锁时,必然存在一个进程资源的循环链
- 死锁的定义
- 死锁的处理方法
- 预防死锁
预防死锁的方法是通过破坏产生死锁的四个必要条件中的一个或几个,从而避免死锁的产生
互斥条件是非共享设备所必须的,不仅不能改变,还应加以保护- 破坏“请求和保持”条件
所有进程在开始运行之前,必须一次性地申请其在整个运行过程中所需的全部资源
只要有一种资源不能满足进程的需求,其他所需的各资源都空闲也不分配给该进程
缺点:- 资源被严重浪费,严重恶化了资源的利用率
- 使进程经常会发生饥饿现象
- 破坏“不可抢占”条件
当一个进程,提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源,以后需要时再重新申请
缺点:- 延长了进程的周转时间
- 增加了系统开销
- 降低了系统吞吐量
- 破坏“循环等待”条件
对系统所有资源类型进行线性排序,并赋予不同的序号,每个进程必须按序号递增的顺序请求资源
缺点:- 限制了新类型设备的增加
- 作业使用各类资源的顺序与系统规定的顺序不同,造成对资源的浪费
- 限制用户简单、自主地编程
- 破坏“请求和保持”条件
- 死锁避免
在资源的动态分配过程中,防止系统进入不安全状态- 系统安全状态
- 安全状态是指系统能按某种进程推进顺序为每个进程
P
i
P_{i}
Pi分配其所需资源,直至满足每个进程对资源的最大需求,使每个进程都可顺利地完成。
此时称 ( P 1 , P 2 , … , P n ) (P_{1},P_{2},\dots,P_{n}) (P1,P2,…,Pn)为安全序列 - 如果系统无法找到这样一个安全序列,则称系统处于不安全状态
- 安全状态是指系统能按某种进程推进顺序为每个进程
P
i
P_{i}
Pi分配其所需资源,直至满足每个进程对资源的最大需求,使每个进程都可顺利地完成。
- 利用银行家算法避免死锁
- 过程
- 需要每种资源类型的最大单元数目
- 首先确定是否有足够的资源分配给该进程
- 有,再进一步计算在将这些资源分配给进程后,是否会使系统进入不安全状态
- 如果不会,才将资源分配给它
- 数据结构
- 可利用资源向量Available:其中每一个元素代表一类可利用的资源数目
- 最大需求矩阵Max:
定义了系统中n个进程中的每一个进程对m类资源的最大需求 - 分配矩阵Allocation:
定义了系统中每一类资源当前已分配给每一进程的资源数 - 需求矩阵Need:表示每个进程尚需的各类资源数
- 过程
- 系统安全状态
- 死锁检测
-
资源分配图
资源分配图中的符号表示
- 圆圈代表一个进程
- 方框代表一类资源
- 方框中的一个点代表一类资源中的一个资源
- 由进程出发到资源的有向边表示请求边
- 由资源出发到进程的有向边表示分配边
资源分配图中有环不一定存在死锁,无环一定没有死锁
-
死锁定理
状态S为死锁状态的充分条件是当且仅当S状态的资源分配图不可完全简化
-
- 死锁解除
- 资源剥夺法
- 终止(或撤消)进程法
- 进程回退法
四种方法,从1到4对死锁的防范程度逐渐减弱,资源利用率的提高,进程因资源因素而阻塞的频度下降(即并发程度提高)
- 预防死锁