一、进程与线程
1. 进程的概念
- 程序:是 静态的,就是个存放在磁盘里的可执行文件,就是一系列的指令集合。
- 进程(Process):是 动态的,是程序的一次执行过程。
- 同一个程序多次执行会对应多个进程
2. 进程的组成
-
PCB 是给 操作系统用的,程序段、数据段 是 给进程自己用的
-
一个 进程实体(进程映像) 由 PCB、程序段、数据段 组成
-
进程是 动态 的,进程实体(进程映像) 是 静态 的。
-
进程 是进程实体的 运行过程,是系统进行 资源分配 和 调度 的一个独立单位
一个进程被“调度”,就是指操作系统决定让这个进程上CPU运行
●PCB
-
当进程被创建时,操作系统会为其分配一个 唯一的、不重复 的“身份证”——PID(Process ID、进程ID)
-
进程控制块(PCB):
PCB是进程存在的唯一标志,当进程被创建时,操作系统为其创建PCB,当进程结束时,会回收其PCB
- 进程描述信息
- 进程标识符PID
- 用户标识符UID
- 进程控制和管理信息
- CPU、磁盘、网络流量使用情况统计…
- 进程当前状态:就绪态/阻塞态/运行态…
- 资源分配清单
- 正在使用哪些文件
- 正在使用哪些内存区域
- 正在使用哪些I/O设备
- 处理机相关信息
- eg. PSW、PC等等各种寄存器的值(用于实现进程切换)
- 进程描述信息
-
这些信息被保存在一个数据结构 PCB 中(Process Control Block)中,即 进程控制块
-
操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会被放在PCB中
●程序段
- 程序的代码(指令序列)
●数据段
- 运行过程中产生的各种数据(eg.程序中定义的变量)
3. 进程的特征
-
动态性:进程是程序的一次执行过程,是动态地产生、变化和消亡的
动态性是进程最基本的特征
-
并发性:内存中有多个进程实体,各进程可并发执行
-
独立性:进程是能独立进行、独立获得资源、独立接受调度的基本单位
-
异步性:各进程按各自独立的、不可预知的速度向前推进,操作系统要提供“进程同步机制”来解决异步问题
异步性会导致并发程序执行结果的不确定性。
-
结构性:每个进程都会配置一个PCB。结构上看,进程由程序段、数据段、PCB组成
4.进程的组织
-
进程的 组成 讨论的是 一个进程内部 由哪些部分构成的问题
-
进程的 组织 讨论的是 多个进程之间 的组织方式问题
进程的组织方式
-
链接方式
- 按照进程状态将PCB分为多个队列
- 操作系统持有指向各个队列的指针
-
索引方式
- 根据进程状态的不同,建立几张索引表
- 操作系统持有指向各个索引表的指针
5. 进程的状态与转换
进程的状态
就绪态、运行态、阻塞态是进程的三种基本状态
进程PCB中会有一个变量state来表示进程的当前状态
-
创建态(New,又称新建态)
进程正在被创建,在这个阶段系统会分配资源、初始化PCB
-
就绪态 (Ready)
进程创建完成后进入“就绪态”,此时进程具备运行条件,但由于没有空闲的CPU,暂不能运行
- 注:进程已有除处理机纸外所需的资源,一旦获得处理机即可进入运行态开始运行。(万事俱备,只欠CPU)
-
运行态 (Running)
占有CPU,并在CPU上运行
-
注:单核处理机:每一时刻最多只有一个进程处于运行态
双核处理机:每一时刻最多可以同时有两个进程处于运行态
-
-
阻塞态 (Waiting/Blocked,又称等待态)
因等待某一事件而暂时不能运行
-
注:如操作系统分配打印机、等待读磁盘操作的结果。
-
为提高CPU利用率,需先将其他进程所需资源分配到位,才能得到CPU的服务。
-
就绪态:有资源、欠CPU
阻塞态:欠资源、欠CPU
-
-
终止态(Terminated,又称结束态)
进程正在从系统中撤销,操作系统会回收进程拥有的资源、撤销PCB
状态间的转换
-
就绪态——>运行态
进程被调度
-
运行态——>就绪态
时间片到,或CPU被其他高优先级的进程抢占
-
运行态——>阻塞态
等待系统资源分配,或等待某事件发生(主动行为)
-
阻塞态——>就绪态
资源分配到位,等待的事件发生(被动行为)
-
创建态——>就绪态
系统完成创建进程的相关操作
-
运行态——>终止态
进程运行结束,或运行过程中遇到不可修复的错误
进程的组织方式(各个进程PCB的组织方式)
6. 进程控制
基本概念
-
概念:进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能
-
如何实现进程控制——原语(运行在 核心态)
-
原语的特点是执行期间 不允许中断 ,只能一气呵成。
-
这种不可被中断的操作即 原子操作 。
-
原语采用 “关中断 指令”和 “ 开中断 指令”实现
- 关/开中断指令 的权限非常大,是只允许在 核心态 下执行的 特权指令
-
原语做的三类事:
-
更新PCB中信息
eg:
- 修改进程状态标志、将运行环境保存到PCB、从PCB恢复运行环境
- 剥夺当前运行进程的CPU的使用权必然需要保存其运行环境
- 某进程开始运行前必然要恢复其运行环境
-
将PCB插入合适的队列
-
分配/回收资源
-
-
相关的原语
(1)进程的创建
- 创建原语(无——>创建态——>就绪态)
- 申请空白PCB
- 为新进程分配所需资源
- 初始化PCB
- 将PCB插入就绪队列(创建态——>就绪态)
- 引起进程创建的事件
- 用户登录
- 分时系统中,用户登录成功,系统会为其建立一个新的进程
- 作业调度
- 多道批处理系统中,有新的作业放入内存时,会为其创建一个新的进程
- 提供服务
- 用户向操作系统提出某些请求,会新建一个进程处理该请求
- 应用请求
- 由用户进程主动请求创建一个子进程
- 用户登录
(2)进程的终止
- 撤销原语(就绪态/阻塞态/运行态——>终止态——>无)
- 从PCB集合中找到终止进程的PCB
- 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程
- 终止其所有子进程(进程间的关系是树形结构)
- 将该进程拥有的所有资源归还给父进程或操作系统
- 删除PCB
- 引起进程终止的事件
- 正常结束:进程请求终止(exit系统调用)
- 异常结束:整数除以0、非法使用特权指令、如何被操作系统强行杀掉
- 外界干预:Ctrl+Alt+delete,用户选择杀掉进程
(3)进程的阻塞和唤醒
阻塞原语和唤醒原语必须成对使用
进程的阻塞
- 阻塞原语(运行态——>阻塞态)
- 找到要阻塞的进程对应的PCB
- 保护进程运行现场,将PCB状态信息设置为“阻塞态”,暂时停止进程运行
- 将PCB插入相应事件的等待队列
- 引起进程阻塞的事件
- 需要等待系统分配某种资源
- 需要等待相互合作的进程完成工作
进程的唤醒
- 唤醒原语(阻塞态——>就绪态)
- 在事件等待队列中找到PCB
- 将PCB从等待队列移除,设置进程为就绪态
- 将PCB插入就绪队列,等待被调度
- 引起进程唤醒的事件
- 等待的事件发生(因何事阻塞,就应由何事唤醒)
(4)进程的切换
- 切换原语(运行态——>阻塞态/就绪态,就绪态——>运行态)
- 将 运行环境信息 存入PCB(进程上下文Context)
- PCB移入相应队列
- 选择另一个进程执行,并更新其PCB
- 根据PCB恢复 新进程所需的运行环境
- 引起进程切换的事件
- 当前进程时间片到
- 由更高优先级的进程到达
- 当前进程主动阻塞
- 当前进程终止
7. 进程通信
- 概念:进程通信是指进程之间的信息交换
- 进程是分配系统资源的单位(包括内存地址空间),因此 各进程 拥有的 内存地址空间相互独立。
共享存储
-
基于数据结构 的共享:
比如共享空间里只能放一个长度为10的数组。
这种共享方式速度慢、限制多,是一种 低级通信 方式。
-
基于存储区 的共享:
在内存中画出一块共享存储区,数据的形式、存放位置都由进程控制,而不是操作系统。
相比之下,这种共享方式速度更快,是一种 高级通信 方式。
管道通信
-
管道只能采用 半双工通信 ,某一时间段内只能实现 单向的传输;
如果要实现 双向同时通信,则 需要设置两个管道。
-
各进程要 互斥 地访问管道。
-
数据以 字符流 的形式写入管道,当 管道写满 时,写进程 的write() 系统调用将被 阻塞,等待读进程将数据取走。
当读进程将数据全部取走后,管道变空,此时 读进程 的read() 系统调用将被 阻塞。
-
如果 没写满,就不允许读。
如果 没读空,就不允许写。
-
数据一旦被读出,就从管道中被抛弃,这意味着 读进程最多只能有一个,否则可能会有读错数据的情况。
消息传递
-
进程间的数据交换以 格式化的消息(Message)为单位。
进程通过操作系统提供的 “发送消息/接收消息” 两个 原语 进行数据交换。
-
直接通信方式
消息直接挂到接收进程的 消息缓冲队列 上
-
间接通信方式
消息要先发送到中间实体(信箱)中,因此也称 “信箱通信方式”。
eg:计网中的电子邮件系统。
8. 线程的概念和多线程模型
线程的概念
- 可以把线程理解为 “轻量级进程”.
- 线程 是一个 基本的CPU执行单元,也是 程序执行流的最小单位。
- 引入线程后,不仅是进程之间可以并发,进程内的 各线程之间 也可以 并发,从而进一步 提升了系统的并发度,使得一个进程内也可以并发处理各种任务(如QQ视频、文字聊天、传文件)
- 引入线程后,进程 只作为 除CPU之外的系统资源的分配单元(如打印机、内存地址空间等都是分配给进程的)。
-
引入线程机制后的变化:
-
线程的属性:
线程的实现方式
-
用户级线程(User-Level Thread,ULT)
-
历史背景:
-
例:
-
很多编程语言提供看强大的线程库,可以实现线程的创建、销毁、调度等功能。
1、用户级线程由 应用程序 通过线程库实现,所有的 线程管理工作 都由 应用程序负责(包括线程切换)。
2、用户级线程中,线程切换 可以在 用户态下即可完成,无需操作系统干预。
3、在用户看来,是有多个线程。但是在操作系统内核看来,并意识不到线程的存在。用户级线程 就是 “从用户视角看能看到的线程”
4、优缺点:
😀 优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高。
😣 缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行。
-
-
内核级线程(Kernel-Level Thread,KLT,又称“内核支持的线程”)
由操作系统支持的线程 1、内核级线程的管理工作 由 操作系统内核 完成。
2、线程调度、切换等工作都由内核负责,因此 内核级线程的切换 必然需要在 核心态 下才能完成。
3、操作系统会为每个内核级线程建立相应的TCB(Thread Control Block,线程控制块),通过TCB对线程进行管理。“内核级线程” 就是 从操作系统内核视角看能看到的线程。
4、优缺点:
😀 优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。
😣 缺点:一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。
多线程模型
-
一对一 模型 :一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同数量的内核级线程。
(优缺点见内核级线程的优缺点)
-
多对一 模型:多个用户级线程映射到一个内核级线程。且一个进程只被分配一个内核级线程。
(优缺点见用户级线程的优缺点)
- 操作系统只 “看得见” 内核级线程,因此只有 内核级线程才是处理机分配的单位 。
-
多对多 模型:n用户级线程映射到m内核级线程( n ≥ m )。每个用户进程对应m个内核级线程。、
克服了多对一模型并发度不高的缺点(一个阻塞全体阻塞);
克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点。
二、处理机调度
1. 调度的概念、层次
调度的基本概念
调度的三个层次
-
高级调度
高级调度(作业调度) :
按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程。每个作业只调入一次,调出一次。作业调入时会建立PCB,调出时才撤销PCB。
-
低级调度
低级调度(进程调度/处理机调度):
按照某种策略从就绪队列中选取一个进程,将处理机分配给它。
进程调度是操作系统中 最基本的一种调度,在一般的操作系统中都必须配置进程调度。
进程调度的 频率很高,一般几十毫秒一次。
-
中级调度
中级调度(内存调度):
按照某种策略决定将哪个处于挂起状态的进程重新调入内存。
一个进程可能会被多次调出、调入内存,因此 中级调度 发生的 频率 要比高级调度 更高。
-
三层调度的联系、对比
【补充知识】进程的挂起态与七状态模型
2. 调度的时机、切换与过程、方式
进程调度的时机
- 进程调度(低级调度),就是按照某种算法从 就绪队列 中选择一个进程为其分配处理机。
-
临界资源:
一个时间段内只允许一个进程使用的资源。各进程需要 互斥地 访问临界资源;
临界区:
访问临界资源的那段代码。
-
进程在 操作系统内核程序临界区 中 不能 进行调度和切换 √
会先上锁
-
进程处于 临界区 时 不能 进行处理机调度×
-
进程调度的方式
-
非剥夺方式
又称 非抢占方式。即,只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态。
实现简单,系统开销小但无法及时处理紧急任务,适合于早期的批处理系统。
-
剥夺调度方式
又称 抢占方式。当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,即立即暂停正在执行的进程,将处理机分配给更重要紧迫的那个进程。
可以优先处理更紧急的进程,也可实现让各进程按时间片轮流执行的功能(通过时钟中断)。适合于分时操作系统、实时操作系统。
进程的切换与过程
-
"狭义的进程调度"与“进程切换”的区别:
-
进程切换的过程主要完成了:
1、对原来运行进程各种数据的保存;
2、对新的进程各种数据的恢复;
(如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块)
注意:
进程切换是有代价的,因此如果 过于频繁的 进行进程 调度、切换,必然会使整个 系统效率降低,使系统大部分时间都花在了进程切换上,而真正用于执行进程的时间减少
本小节不是考试重点,但需要理解。
3. 调度算法的评价指标
CPU利用率
CPU造价昂贵,希望让CPU尽可能多地工作
-
CPU利用率:
指 CPU “忙碌” 的时间占总时间的比例。
-
利用率:
利 用 率 = 忙 碌 的 时 间 总 时 间 利用率=\frac{忙碌的时间}{总时间} 利用率=总时间忙碌的时间
eg:
系统吞吐量
对于计算机来说,希望能用尽可能少的时间处理完尽可能多的作业
-
系统吞吐量
单位时间内完成作业的数量
系 统 吞 吐 量 = 总 共 完 成 了 多 少 道 作 业 总 共 花 了 多 少 时 间 系统吞吐量=\frac{总共完成了多少道作业}{总共花了多少时间} 系统吞吐量=总共花了多少时间总共完成了多少道作业
eg:
周转时间
对于计算机来说,他很关心自己的作业从提交到完成花了多少时间
-
周转时间
是指 作业被提交给系统开始,到 作业完成为止 的这段时间间隔
它包括四个部分:
1、作业在外存后备队列上等待作业调度(高级调度)的时间
2、进程在就绪队列上等待进程调度(低级调度)的时间
3、进程在CPU上执行的时间
4、进程等待 I/O 操作完成的时间
后三项在一个作业的整个处理过程中,可能发生多次
-
(作业)周转时间
( 作 业 ) 周 转 时 间 = 作 业 完 成 时 间 − 作 业 提 交 时 间 (作业)周转时间=作业完成时间-作业提交时间 (作业)周转时间=作业完成时间−作业提交时间
对于用户来说,跟关心自己的单个作业的周转时间 -
平均周转时间
平 均 周 转 时 间 = 各 作 业 周 转 时 间 之 和 作 业 数 平均周转时间=\frac{各作业周转时间之和}{作业数} 平均周转时间=作业数各作业周转时间之和
对于操作系统来说,更关心系统的整体表现,因此更关心所有作业周转时间的平均值
- 带权周转时间
带 权 周 转 时 间 = 作 业 周 转 时 间 作 业 实 际 运 行 的 时 间 = 作 业 完 成 时 间 − 作 业 提 交 时 间 作 业 实 际 运 行 的 时 间 带权周转时间=\frac{作业周转时间}{作业实际运行的时间}=\frac{作业完成时间-作业提交时间}{作业实际运行的时间} 带权周转时间=作业实际运行的时间作业周转时间=作业实际运行的时间作业完成时间−作业提交时间
带权周转时间必然≥1
带权周转时间与周转时间都是越小越好
- 平均带权周转时间
平 均 带 权 周 转 时 间 = 各 作 业 带 权 周 转 时 间 之 和 作 业 数 平均带权周转时间=\frac{各作业带权周转时间之和}{作业数} 平均带权周转时间=作业数各作业带权周转时间之和
-
等待时间
计算机的用户希望自己的作业尽可能少的等待处理机
-
等待时间
指进程/作业 处于等待处理机状态时间之和,等待时间越长,用户满意度越低。
对于 进程 来说,等待时间就是指进程建立后 等待被服务的时间之和,在等待I/O完成的期间其实进程也是在被服务的,所以不计入等待时间。
对于 作业 来说,不仅要考虑 建立进程后的等待时间,还要加上作业在外村后备队列中等待的时间。
一个作业总共需要被CPU服务多久,被I/O设备服务多久一般是确定不变的,因此调度算法其实只会影响作业/进程的等待时间。
与前面指标类似,也有“平均等待时间”来评价整体性能。
响应时间
对于计算机用户来说,希望自己的提交的请求(比如通过键盘输入了一个调试命令)尽早地开始被系统服务、回应。
-
响应时间
指从用户 提交请求 到 首次产生响应 所用的时间
4. 调度算法:FCFS、SJF、HRRN
FCFS 先来先服务
FCFS——First Come First Serve
-
算法思想:主要从“公平”角度考虑
-
算法规则:按照作业/进程到达的先后顺序进行服务
-
用于作业/进程调度:
用于作业调度时,考虑的是哪个作业先到达后备队列;
用于进程调度时,考虑的是哪个进程先到达就绪队列;
-
是否可抢占: 非抢占式的算法
-
优缺点:
优点:公平、算法实现简单
缺点:排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好。即,FCDS算法 对长作业有利,对短作业不利
-
是否会导致 饥饿:不会 (只要等就会轮到)
补充:饥饿:指某进程/作业长期得不到服务
例:
注意到P3的带权周转时间很大,这意味着P3本来需要很少的时间运行,却等待了很长时间。
SJF 短作业优先
SJF——Shortest Job First
-
算法思想:追求最少的平均等待时间,最少的平均周转时间、最少的平均平均带权周转时间
-
算法规则:最短的作业/进程优先得到服务(所谓“最短”,指要求服务时间最短)
-
用于作业/进程调度:
即可用于作业调度,也可用于进程调度。
用于进程调度时称为 “短进程优先(SPF,Shortest Process First)算法”;
-
是否可抢占: SJF和SPF是 非抢占式的 算法,但是 也有抢占式的版本—— 最短剩余时间优先 算法(SRTN,Shortest Remaining Time Next)
-
优缺点:
优点:“最短的” 平均等待时间、平均周转时间
缺点:不公平。 对短作业有利,对长作业不利。可能产生 饥饿现象。另外,作业/进程的运行时间是由用户提供的,并不一定真实,不一定能做到真正的短作业优先。
-
是否会导致 饥饿:会
如果源源不断的有短作业/进程到来,可能使长作业/进程长时间得不到服务,产生 “ 饥饿 ”现象。如果一直得不到服务,则称为 “ 饿死 ”
例:
非抢占式:
抢占式:
注意点:
HRRN 高响应比优先
HRRN——Highest Response Ratio Next
-
算法思想:要综合考虑作业/进程的等待时间和要求服务的时间
-
算法规则:在每次调度时先计算各个作业/进程的 响应比,选择 响应比最高的 作业/进程为其服务.
响 应 比 = 等 待 时 间 + 要 求 服 务 时 间 要 求 服 务 时 间 响应比 = \frac{等待时间+要求服务时间}{要求服务时间} 响应比=要求服务时间等待时间+要求服务时间
响应比 ≥ 1 -
用于作业/进程调度:即可用于作业调度,也可用于进程调度。
-
是否可抢占: 非抢占式的 算法,因此只有当前运行的作业/进程主动放弃处理机时,才需要调度,才需要计算响应比
-
优缺点:
优点:综合考虑了等待时间和运行时间(要求服务时间)
等待时间相同时,要求服务时间短的优先(SJF的优点)
要求服务时间相同时,等待时间长的优先(FCFS的优点)
对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题
-
是否会导致 饥饿:不会
例:
要动手算,算法特性容易考小题,算法的使用常结合调度算法的评价指标在大题中考察
5. 调度算法:时间片轮转、优先级、多级反馈队列
时间片轮转(RR)
RR——Round-Robin
-
算法思想:公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应
-
算法规则:按照各进程到达就绪队列的顺序,轮流让各个进程执行一个 时间片 (如100ms)。若进程未在一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队
-
用于作业/进程调度:用于进程调度(只要作业放入内存建立了相应的进程后,才能被分配处理机时间片)
-
是否可抢占: 若进程未能在时间片内运行完,将被强行剥夺处理机使用权,因此时间片轮转调度算法属于 抢占式 的算法。由 时钟装置 发出 时钟中断 来通知 CPU 时间片已到
-
优缺点:
优点:公平,响应快,适用于 分时操作系统
缺点:由于高频率的进程切换,因此有一定开销;不区分任务的紧急程度
-
是否会导致 饥饿:不会
例:
时间片大小为2时:
时间片大小为5时:
和先来先服务调度算法对比:
可以看到当时间片大小为5时和先来先服务算法是一致的
- 补充:时间片太大或太小会有什么影响?(选择题中常考察)
1)如果 时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法 退化为先来先服务 调度算法,并且会 增大响应时间。因此 时间片不能太大。
2)进程调度、切换是有时间代价的(保存、恢复运行环境),因此如果 时间片太小,会导致 进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少。可见, 时间片也不能太小。
优先级
-
算法思想:随着计算机的发展,特别是实时操作系统的出现,越来越多的应用场景需要根据任务的紧急程度来决定处理顺序
-
算法规则:调度时选择优先级最高的作业/进程
-
用于作业/进程调度:即可用于作业调度,也可用于进程调度。甚至,还会用于之后学习的 I/O 调度中
-
是否可抢占: 抢占式、非抢占式都有。
非抢占式:只需在进程主动放弃处理机时进行调度即可
抢占式:需要在就绪队列变化时,检查是否会发生抢占
-
优缺点:
优点:用优先级区分紧急程度、重要程度,适用于 实时操作系统。可灵活地调整对各种作业/进程的偏好程度
缺点:若源源不断地有高优先级进程到来,则可能导致饥饿
-
是否会导致 饥饿:会
例:
(优先级和优先数不是一个意思,注意题意进行区分,有的题可能优先数越小优先级越高)
非抢占式:
抢占式:
- 补充:
多级反馈队列
-
算法思想:对其他调度算法的折中权衡
-
算法规则:
1)设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
2)新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回该队列队尾
3)只有第 k 级队列为空时,才会为 k + 1 级对头的进程分配时间片
-
用于作业/进程调度:用于进程调度。
-
是否可抢占: 抢占式 的算法。
在k级队列的进程运行过程中,若更上级的队列(1~k-1级)中进入了一个新进程,则由于新进程处于优先级更高的队列中,因此新进程会抢占处理机,原来运行的进程放回k级队列队尾
-
优缺点:
优点:
对各类型进程相对公平(FCFS的优点);
每个新到达的进程都可以很快就得到响应(RR的优点);
短进程只用较少的时间就可完成(SPF的优点);
不必实现估计进程的运行时间(避免用户作假);
可灵活地调整对各类进程的偏好程度,比如CPU密集型进程、I/O密集型进程(拓展:可将因I/O而阻塞的进程重新放回原对了,这样I/O型进程就可以保持较高优先级)
缺点:可能导致饥饿
-
是否会导致 饥饿:会
例:
三、进程同步
1. 进程同步、进程互斥
什么是 进程同步
回顾:进程具有 异步性 的特征。异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。
操作系统提供 ” 进程同步 机制 “ 来实现 ” 预知 “ 需求
如:
另一个例子:
同步 亦称 直接制约关系,它是指完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上 协调 它们的 工作次序 而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作。
什么是 进程互斥
-
临界资源:
我们把 一个时间段内只允许一个进程使用 的资源称为 临界资源。
许多设备(如:摄像头、打印机)都属于临界资源,此外还有许多变量、数据、内存缓冲区等都属于临界资源。
对临界资源的访问,必须 互斥 地进行。互斥,亦称 间接制约关系。进程互斥 指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当访问临界资源的进程访问结束,释放该资源后,另一个进程才能去访问临界资源。
-
对临界资源的互斥访问,可在逻辑上分为如下四部分:
临界区 是进程中 访问临界资源 的代码段 进入区 和 退出区 是 负责实现互斥 的代码段 临界区也可称为“临界段” -
为实现对临界资源的互斥访问,同时保证系统整体性能,需遵循:
1)空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;
2)忙则等待。当已有进程进入临界区时,其他试图进图临界区的进程必须等待;
3)有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿);
4)让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
2. 实现临界区互斥的基本方法
进程互斥的软件实现方法
如果不互斥访问:
如何实现进程互斥:
● 单标志法
● 双标志先检查
若两进程并发运行,会产生问题:
● 双标志后检查
可能会产生都在等待的情况:
● Peterson算法
Peterson 算法用软件方法解决了进程互斥问题,遵循了空闲让进、忙则等待、有限等待三个原则,但是依然 未遵循让权等待 的原则。
(因为进程进不了临界区,一直被卡在while循环中,一直还在CPU上执行,不断检查while循环的条件,会占用CPU资源,未满足让权等待原则)
Peterson 算法较前三种方案来说是最好的,但还不够好。
抓住 “谦让” 和 “表达意愿”
进程互斥的硬件实现方法
● 中断屏蔽方法
● TestAndSet(TS指令/TSL指令)
● Swap指令(XCHG指令)
3. 信号量
本小节常考
信号量机制
用户进程可以通过使用操作系统提供的 一对原语 来对 信号量 进行操作,从而很方便的实现了进程互斥、进程同步。
-
信号量:
其实就是一个变量 可以是一个整数,也可以是更复杂的记录型变量。
可以用一个信号量来 表示系统中某种资源的数量,比如:系统中只有一台打印机,就可设置一个初值为1的信号量。
注意 一个信号量对应一种资源
-
原语:
是一种特殊的程序段,其 执行只能一气呵成,不可被中断。原语是由 关中断/开中断指令 实现的。
软件解决方案的主要问题是由 “进入区的各种操作无法一气呵成”,因此如果能把进入区、退出区的操作都用 “原语” 实现,使这些操作能 “一气呵成” 就能避免问题。
-
一对原语:
● 整型信号量
● 记录型信号量
如:
Tip:
单词联想记忆法:
(1)P对应单词pause,即暂停的意思,行动前先暂停检查下可用资源,等待(wait)到资源后即可行动;
(2)V对应单词,victory,行动胜利即凯旋卸甲(释放资源)
该记忆法源自网络
用信号量实现进程互斥
用信号量实现进程同步
进程同步:
实现进程同步:
更复杂的同步问题:
4. 经典同步问题
● 生产者-消费者问题
消费者进程从缓冲区取出数据,若生产者进程处于阻塞态,消费者进程需将其唤醒,使生产者进程处于就绪态(生产者进程不会立即往缓冲区填数据)。
如果进程同时访问临界区,可能会出现问题,如两个生产者进程,可能会向同一块区域写入数据,造成数据覆盖,所以要互斥地访问。
- 思考:能否改变相邻P、V操作的顺序?
生产和使用产品能否放到PV之间:
逻辑上是可以的。但是会使临界区代码变得更长,也就是说一个进程对临界区上锁的时间会变得更长,不利于各个进程交替的使用临界区资源,因此临界区代码要尽可能短。所以实际上不建议放在PV之间。
重要考点:
实现互斥的P操作要在实现同步的P操作之后,否则会导致死锁问题。
● 多生产者-多消费者问题
-
问题描述:
不同的生产者和消费者所生产和消费的东西是不一样的,多指 “多类”
-
问题分析:
1、关系分析:
2、整理思路:根据各进程操作流程确定P、V操作顺序
互斥:在临界区前后分别 PV;
同步:前 V 后 P。
3、设置信号量:
互斥信号量初值一般为1;
同步信号量初值要看对应资源的初始值是多少。
-
实现:
能否去掉互斥信号量?👇
即使不设置专门的互斥变量 mutex,也不会出现多个进程同时访问盘子的现象。
原因在于:此题缓冲区大小为1,在任何时刻,apple、orange、plate三个同步信号量中最多只有一个是1。因此在任何时刻,最多只有一个进程的P操作不会被阻塞,并顺利地进入临界区。
若将盘子容量改为2,即缓冲区大小为2:
-
重要考点:
从 “事件” 角度考虑:
● 吸烟者问题
-
问题描述:
生产者生产多种产品
-
问题分析:
1、分析关系:
2、整理思路
3、设置信号量
-
实现:
是否需要设置一个专门的互斥信号量?
不需要。缓冲区大小为1,同一时刻,四个同步信号量中至多有一个的值为1.
-
重要考点:
● 读者写者问题
-
问题描述:
读者——读,写者——写
-
问题分析:
-
实现:
count 解决读者和读者之间可能不能同时访问的问题:
但是起初的 “加锁” 操作可能仍然会有两个读者 “同时” 进行,如 1进程 判断 count == 0 后,在进行 P(rw) 之前切换到 2进程,此时 2进程 同样可以 判断 count == 0 ,进行 P(rw) 操作使 rw = 0,等进程切回 1 时,1进程会被阻塞在 P 操作那。
多增加一个互斥信号量:
但是仍然存在 写进程饿死 的问题,再增加一个信号量:
-
重要考点:
● 哲学家进餐问题
-
问题描述:
-
问题分析:
-
实现:
每个哲学家吃饭前依次拿起左、右两支筷子
如何防止死锁发生?
或者:
即
-
重要考点:
5. 管程
引入管程的原因:
-
管程的定义
有点像 面向对象中的类
-
管程的基本特征
● 拓展1:用管程解决生产者消费者问题
引入管程的目的是更方便地实现进程互斥和同步:
● 拓展2:Java中类似管程的机制
四、死锁
1. 死锁的概念
-
什么是死锁
在并发环境下,各进程因竞争资源而造成的一种 相互等待对方手里资源,导致各进程都阻塞,都无法向前推进 的现象,就是 “死锁” 。
发生死锁后,若无外力干涉,这些进程都将无法向前推进。
-
死锁、饥饿、死循环的区别
容易在选择中考察
-
死锁产生的必要条件
如果同类资源数> 1,则即使有循环等待,也未必发生死锁。(如上图所示)
如果系统中每类资源都只有一个,那循环等待就是死锁的充分必要条件了。
-
什么时候会发生死锁
-
死锁的处理策略
2. 预防死锁(静态策略)
-
破坏互斥条件
-
破坏不剥夺条件
-
破坏请求和保持条件
-
破坏循环等待条件
3. 避免死锁(动态策略)
银行家算法
🔴 本节重要
什么是安全序列
例:
Ⅰ、若B还想借30亿
此时借给B的30亿是不安全的…
Ⅱ、若A还想借20亿
如上答应A的请求,按 T -> B -> A 的顺序借钱是 OK 的;按 A -> T -> B 的顺序也 OK。
所以借给A的20亿是安全的…
-
安全序列
-
安全状态
如在上例 借给B 30亿后是不安全的,如果BAT没有提出再借20亿的请求,虽然系统处于不安全状态,但是还未发生死锁。(该点容易考察选择题)
因此可以在 资源分配之前预先判断这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求。(这也是 银行家算法 的核心思想)
银行家算法
- 例子说明:
1)资源总数(10,5,7),剩余可用资源(3,3,2)
将剩余可用资源与每个进程最多还需多少资源进行比对:
2)资源总数(10,5,7),剩余可用资源(5,3,2)
重新进行新一轮比对:
3)资源总数(10,5,7),剩余可用资源(7,4,3)
实际做题(手算)方法:
找不到安全序列的例子:
- 代码实现思路
其中:
① 表示判断此次 i 申请的资源是否大于 i 所承诺的要申请的最大资源的数量;
② 表示判断系统中剩余的资源是否能满足此次 i 申请的资源;
③ 改变了三组数据,上例中执行第③步后修改如下:
- 知识回顾与重要考点
4. 死锁检测和解除
死锁的检测
检测:(例)
eg:
死锁的解除
解除死锁的主要方法:
1、资源剥夺法
如何决定 “对谁动手”: