进程管理
进程引入
前趋图
- P_i -> P_j, (P_i, P_j)
进程执行方式
-
顺序执行
- 顺序性
- 封闭性
- 可再现性
-
并发执行
- 间断性
- 不封闭性
- 不可再现性(异步性)
进程的定义
定义
- 程序的一次执行过程
进程的特征
-
动态性
- 进程因创建而产生,调度而执行,得不到资源而阻塞,撤销而消亡
-
并发性
- 可并发执行
-
独立性
- 进程时资源分配和调度的基本单位
-
异步性
- 进程以未知的方向向前推进
进程和程序的关系
-
动态性与静态性
- 程序是代码段
- 进程时程序的过程
-
组成不同
- 程序是程序段
- 进程是 PCB+程序段+数据段
进程和作业的区别
-
作业的概念
- 用户要求计算机执行的任务的集合
-
区别
- 作业是任务实体,进程是执行实体
- 一个作业可以由多个进程组成
进程的组成
-
进程=PCB+程序段+数据段
-
PCB的组成
- 优先级
- 指向下一个PCB的指针
- …
PCB 的作用
- 作用
- 为何PCB是进程存在的唯一标志?
进程的状态与转换
进程的状态
- 就绪
- 执行
- 阻塞
- 创建
- 结束
进程状态的转换
进程控制
进程控制都是通过【原语】实现的
进程创建
-
引起进程创建的事件
- 用户登录
- 作业调度
- 请求服务-创建子进程
-
创建原语的实现
-
- 申请空白 PCB,指定 PID
-
- 为进程分配必要的资源
-
- 初始化 PCB
-
- 将新进程的 PCB 插入到就绪队列
-
进程撤销
-
两种撤销策略
- 撤销指定进程
- 撤销进程及其子孙进程
-
撤销原语的实现
-
- 在 PCB 集合中找到要撤销的进程的 PCB
-
- 若进程正在执行,则停止它,并设置调度标志
-
- 对于后一种调度策略,要把子孙进程也给撤销了
-
- 回收撤销进程占有的资源,还给父进程或系统,回收 PCB
-
进程的阻塞与唤醒
-
阻塞原语
-
特性
- 进程的阻塞是一种【主动行为】,只能是进程阻塞自己
-
实现
-
- 停止进程的运行,中断处理器
-
- 保存 CPU 现场
-
- 将进程插入到相应事件的等待队列
-
- 进行进程调度,选一个新进程运行
-
-
-
唤醒原语
-
特性
- 唤醒原语是发现者进程调用的,对于阻塞进程而言是【被动行为】
-
实现
-
- 将进程的 PCB 从等待队列中移出
-
- 将 PCB 插入到就绪队列
-
-
线程
线程的引入
-
进程的独立性
-
- 拥有资源的基本单位
-
- 处理器调度和分配的基本单位
- 缺点:进程的 PCB 在进程状态改变的时候会飞来飞去(从一个队列中移出并插入到另一个队列),时空开销大
- 使用线程代替这一个功能
-
线程的定义
- 从进程中划分出多个线程
- 线程可以共享进程的数据
线程的实现
-
内核级线程
-
定义
- 由内核完成线程控制(线程的创建、阻塞、撤销等)
-
特点
- 一个内核级线程由于 I/O 阻塞,不会影响其他线程的运行
- 时间片分配的对象是线程
-
-
用户级线程
-
定义
- 由应用程序利用线程库完成线程的控制
-
特点
- 当一个线程阻塞,整个线程必须等待
- 时间片的分配对象是进程
-
线程和进程的比较
-
调度
-
线程
- 独立调度的基本单位
-
进程
- 拥有资源的基本单位
-
-
拥有资源
-
线程
- 不拥有资源,可以访问进程的资源
-
进程
- 拥有系统资源
-
-
并发性
-
线程
- 高
-
-
系统开销
-
线程
- 小
-
多线程模型
- 多对一模型
- 一对一模型
- 多对多模型
进程通信
通信方式分类
-
低级进程通信
- 交换的数据量小,如 PV 原语
-
高级进程通信
高级进程通信
-
共享存储器
-
消息传递系统
- 直接通信方式
- 间接通信方式
-
管道通信系统
进程调度
处理器的三级调度
-
高级调度(作业调度)
-
实体变化
- 作业 -> 进程
-
状态变化
- 无 -> 就绪
-
-
中级调度
-
实体变化
- 外存 <-> 内存
-
状态变化
- 挂起 <-> 就绪
-
-
低级调度(进程调度)
-
实体变化
- 进程 -> 进程
-
状态变化
- 就绪 -> 执行
-
调度算法的评估指标
-
CPU 利用率
-
系统吞吐量
- 单位时间内完成的作业的数量
-
周转时间
-
定义:周转时间 = 完成时间 - 到达时间
-
周转时间的组成
-
- 等待作业调度的时间
-
- 等待进程调度的时间
-
- 在 CPU 上执行的时间
-
- I/O 阻塞的时间
-
-
-
平均周转时间
-
带权周转时间
-
平均带权周转时间
进程调度的功能
- 记录系统中所有进程的有关情况及状态信息
- 选择获得处理器的进程
- 处理器现场的保护与恢复
引起进程调度的原因
-
两种情况
- 有进程使用 CPU
- 归还 CPU
-
例子
- 进程运行结束
- 进程变为阻塞态
- 执行完系统调用等系统程序(执行完系统调用返回用户进程时,可以视为系统进程执行完毕,从而可以调度一个新的用户进程执行)
- 抢占式获得处理器(与调度方式有关)
- 时间片用完(与系统类型有关)
不能进行进程调度的情况
- 处理中断的过程中
- 原子操作的过程中
- 内核程序临界区
进程调度的方式
- 抢占
- 非抢占
进程调度算法
本质:制定 PCB 在就绪队列中的顺序
-
先来先服务 FCFS
-
描述
- 按进程进入就绪队列的先后次序分配处理器
-
特点
- 利于长进程,不利于短进程
-
-
短作业优先 SJF
-
描述
- 优先把处理器分配给最快完成的进程
-
特点
- 不利于长进程
- 可能会出现“饥饿”现象
-
-
优先级调度算法
-
描述
- 优先把处理器分配给优先级高的进程,算法性能取决于优先级的设定
-
优先级分类
-
静态优先级
- 进程类型
- 资源要求
- 用户类型和要求
-
动态优先级
- 占有 CPU 时间的长短
- 等待 CPU 时间的长短
- 是否为抢占式
-
-
-
时间片轮转调度算法
-
特点
-
算法性能取决于时间片大小
-
时间片太小
- 时间浪费在进程切换上
-
时间片太大
- 算法退化为 FCFS
-
-
-
决定时间片大小的因素
-
系统响应时间
- T = N*q
-
就绪队列中的进程数 q
-
计算机的计算速度
-
-
-
高响应比优先调度
-
响应比计算
- (等待时间+运行时间) / 运行时间
-
描述
- 先计算就绪队列中每个作业的响应比,挑响应比最高的作业运行
-
-
多级反馈队列调度
-
描述
- 设置多个就绪队列,越往后,进程的优先级越小并且时间片的大小越大。当一个进程进入时,先进入第一个队列,按 FCFS 排队,如果第一个作业不能在一个时间片内执行完,则移动到下一个队列当中,到了最后一个队列变为时间片轮转调度算法。当一个进程正在使用处理器,别的优先级更高的进程进入队列时,优先级高进程将抢占 CPU
-
死锁
概念
- 多个进程因竞争系统资源或相互通信而处于永久阻塞状态,若无外力作用,这些进程都无法向前推进
死锁产生的原因
- 系统资源不足
- 进程推进顺序不当
死锁产生的必要条件
- 互斥条件
- 不剥夺条件
- 请求与保持条件
- 环路等待条件
处理死锁的方法
- 鸵鸟算法
- 死锁预防
- 死锁避免
- 死锁检测与解除
死锁预防
-
操作:破坏死锁产生的必要条件之一
-
破坏互斥
- 不太现实,这个方法取决于资源本身的属性,如果资源本身只能互斥访问,像打印机这种就没辙了
-
破坏不剥夺
- 1.使用抢占的方式
-
- 对于一个已经申请了某些资源的进程,如果申请新的资源的请求不能得到满足,必须释放所有已经申请的资源
-
破坏请求与保持
- 在进程运行之前,就预先把进程运行需要是所有资源一次性分配给它
-
破坏环路等待
- 有序资源分配法
死锁避免
-
两种状态
-
安全状态
- 系统不会发生死锁的状态
-
不安全状态
- 系统有可能发生死锁的状态
-
注意
- 不安全状态不一定会发生死锁,死锁状态的系统一定是不安全状态
-
-
银行家算法
-
前置定义
- n 个进程,m 类资源
-
数据结构
-
Available 1*m
- 某类资源的空闲资源数量
-
Max n*m
- 进程对某类资源的最大需求量
-
Allocation n*m
- 系统已分配给某类进程的某类资源的数量
-
Need n*m
- 某类进程还需要某类资源的数量
-
关系
- Need[i][j] = Max[i][j] - Allocation[i][j]
-
-
算法描述
-
前置说明
- Request_i[j] = k 表示进程 i 请求 j 资源的个数为 k
- 如果题目没有给你说进程请求资源,就让你判断系统状态,直接执行安全算法(因为无情的我已经快刷完第二章的题了)
-
① 检查
-
k <= Need[i][j]
- 是,则执行 ②
- 否则,raise error
-
k <= Available[i][j]
- 是,则执行 ③
- 否则,进程 i 等待资源
-
-
② 预分配
- Available -= k
- Allocation += k
- Need -= k
-
③ 安全算法
- 书本上偏要深复制一个新的向量 Work,咱这直接用 Available 来说吧
- 1)设置一个标记数组 flag[i] = {false}
- 2)找到一个满足条件的进程 i ,让 Need[i] < Available。如果找到了,跳到 ③;如果没找到,break,系统处于不安全状态
- 3)Available += Allocation[i], flag[i] = true
- 4)最后如果 flag 的所有元素均为 true 则系统处于安全状态
-
安全家算法的做题写法规范
- 借鉴群力哥的 ppt 的,如下
-
-
死锁的检测与解除
-
资源分配图
- 节点和边的概念及形状
-
死锁定理
- 通过简化资源分配图来检测系统是否是死锁状态
-
死锁检测算法
- 类似安全算法
-
死锁解除
- 剥夺资源
- 撤销进程
- 进程回退
区分
-
忙等
- 一直在检测某个循环条件
-
死等
- 死等 = 死锁
-
死锁
- 你阻塞了,我也阻塞了,没辙了
-
饥饿
- 产生饥饿的原因
- 进程调度策略(如短任务优先调度策略)
- 死锁 or 活锁 (死锁状态是饥饿状态的子集)
- 饥饿可以是就绪状态,死锁是阻塞状态
- 产生饥饿的原因
-
饿死
- 饥饿到一定程度就是饿死
-
活锁
- 忙等下发生的饥饿
同步与互斥
互斥(间接相互制约)
-
概述
- 多个同类进程需要互斥访问某种系统资源
-
形式
- 进程-资源-进程
同步(直接相互制约)
-
概念
- 多个不同类进程在一些关键点上协调工作次序进行相互等待与相互交换信息(说白了是顺序问题,谁先谁后)
-
形式
- 进程-进程
临界资源与临界区
-
临界资源
- 同一时刻只允许一个进程使用的资源
-
临界区
- 访问临界资源的代码
互斥的要求
- 空闲让进
- 忙则等待
- 有限等待
- 让权等待
互斥的实现方法
-
硬件方法(不考)
-
软件方法-4个算法
-
变量含义
-
turn
- 表示是否允许进 -> turn=0 表示只允许 P_0 进入
-
flag
- 表示想不想进 -> flag[1]=true 表示P_1 想进
-
-
算法一
int turn = 0; P_o(){ while(1){ while(turn != 0) ;等待 进入临界区; turn = 1; } }
-
问题
- 强制不同进程交替进入临界区,不能保证“空闲让进”
-
-
算法二
bool flag[2] = {false, false}; P_o(){ while(1){ while(flag[1]) ;等待 flag[0] = true; 进入临界区; flag[1] = false; } }
-
问题
- 当两个进程同时进入时,违背“忙则等待”
-
-
算法三
bool flag[2] = {false, false}; P_o(){ while(1){ flag[0] = true; while(flag[1]) ;等待 进入临界区; flag[1] = false; } }
-
问题
- 当两个进程同时进入时,发生“死等”/“死锁”,违背“有限等待”
-
-
算法四
int turn; bool flag[2] = {false, false}; P_o(){ while(1){ flag[0] = true; turn = 1; while(flag[1] && turn) ;等待 进入临界区; flag[1] = false; } }
-
课本上之所以说 turn 变量解决了 “饥饿”,是因为 turn 变量使得进程不会产生死锁现象,以解决“饥饿”
信号量
-
信号量分类
-
整型信号量
-
结构
- 光一个 S
-
特点
- 存在“忙等”
-
-
记录型信号量
-
结构
- 二元组 (S, q)
-
特点
- 遵循“让权等待”
-
-
AND 型信号量(不考)
-
-
记录型信号量值的含义
-
S >= 0
- 空闲资源数
-
S < 0
- 阻塞进程数
-
-
PV原语
-
P原语的执行过程
-
- S = S - 1
-
S >= 0
- 进程继续运行
-
S < 0
- 进程阻塞
-
-
V原语的执行过程
-
- S = S + 1
-
S > 0
- 进程继续运行
-
S <= 0
- 从等待队列移出进程,插入就绪队列
-
-
经典同步问题
-
生产者-消费者问题
-
同步关系
- 当缓冲区为空,只能由生产者程序执行
- 当缓冲区为满,只能由消费者程序执行
- 多个进程互斥访问缓冲区
-
注意事项
- 对互斥信号量的 P 操作要放在对资源信号量的 P 操作之后
- 如果有多个生产者和消费者,需要设置互斥信号量,互斥地访问缓冲区
-
-
读者-写者问题
-
前置条件
- 多个读者可以同时读
- 多个写者不能同时写
- 一个写者在进行写操作的时候,其他的进程必须等待
-
读者优先算法
-
公平竞争算法
-
-
哲学家进餐问题
-
四种解决办法
-
- 先让奇数号哲学家进餐,再让偶数号哲学家进餐
-
- 奇数号哲学家先拿右边的筷子,再拿左边筷子;偶数号哲学家反之
-
- 同时只允许n -1 个哲学家进餐
-
-
-
PV 类题方法总结
补充-资源分配图化简
- 看资源,把资源分配给进程
- 看进程,进程是否阻塞(能申请到所有的资源),阻塞的进程不管,如果进程不会阻塞(申请到了所需的所有资源),返还此进程占用的资源
- 重复1,2 步骤,如果最后资源分配图中有剩下的边,则会产生死锁,如果没有剩下的边则不会产生死锁