进程的概念、组成、特征
- 概念:进程是进程实体的运行过程,是系统进行==资源分配==和==调度==的一个独立单位
调度(Scheduling) 是操作系统管理计算机资源(如CPU、内存、I/O设备)的核心机制
- 组成
- PCB(进程控制块):但凡操作系统管理时所需要的信息,都会被放在PCB中。==是进程存在的唯一标志==
- 进程描述信息
- 进程标识符PID:==唯一的、不重复的==
- 用户标识符UID
- 进程控制和管理信息
- CPU、磁盘、网络流量使用情况统计…
- 进程当前状态:就绪态/阻塞态/运行态…
- 资源分配清单
- 正在使用哪些文件
- 正在使用哪些内存区域
- 正在使用哪些I/O设备
- 处理机相关信息
- 如PSW、PC等等各种寄存器的值(用于实现进程切换)
- 进程描述信息
- 程序段:程序的代码(指令序列)
- 数据段:运行过程中产生的各种数据(如:程序中定义的变量)
- PCB(进程控制块):但凡操作系统管理时所需要的信息,都会被放在PCB中。==是进程存在的唯一标志==
- 特征
- 动态性
- 进程是程序的一次执行过程,是动态地产生、变化和消亡的
- 进程的==最基本特性==
- 并发性
- 内存中有很多进程实体,各进程可并发执行
- 独立性
- 进程是能独立运行、独立获得资源、独立接受调度的基本单位
- 异步性
- 各进程以不可预知的速度向前推进,可能导致运行结果的不确定性
- 操作系统要提供“进程同步机制”来解决异步问题
- 结构性
- 每个进程都会配置一个PCB。从结构上看,进程是由PCB、程序段、数据段组成
- 动态性
进程的状态与转换
状态
- 运行状态:CPU✅其他所需资源✅
- 就绪状态:CPU❌其他所需资源✅
- 阻塞状态:CPU❌其他所需资源❌
- 创建状态:操作系统为新进程分配资源、创建PCB
- 终止状态:操作系统回收进程的资源、撤销PCB
进程状态间的转换
就绪态$\Longrightarrow$运行态:进程被调度
运行态$\Longrightarrow$就绪态:时间片到,或CPU被其他高优先级的进程抢占
运行态$\Longrightarrow$阻塞态:等待系统资源分配,或等待某事件发生(主动行为)
阻塞态$\Longrightarrow$就绪态:资源分配到位,等待的时间发生(被动行为)
创建态$\Longrightarrow$就绪态:系统完成创建进程相关的工作
运行态$\Longrightarrow$终止态:进程运行结束,或运行过程中遇到不可修复的错误
进程控制
基本概念:
- 进程控制就是要实现进程状态的转换
![进程状态转换]()
- 进程控制用原语实现
- 原语用==关/开中断==来实现
- 原语是一种特殊的程序
- 原语的执行必须==一气呵成、不可中断==
相关原语
- 进程的创建
- 创建原语
- 申请空白PCB
- 为新进程分配所需资源(内存,空间)
- 初始化PCB
- 将PCB插入就绪队列
- 引起进程创建的事件
- 用户登录:分时系统中,用户登录成功,系统会为其建立一个新的进程
- 作业调度:多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程
- 提供服务:用户向操作系统提出某些请求时,会新建一个进程处理该请求
- 应用请求:由用户进程主动请求创建一个子进程
- 创建原语
- 进程的终止
- 撤销原语(就绪态/阻塞态/运行态$\Longrightarrow$ 终止态$\Longrightarrow$ 无)
- 从PCB集合中找到终止进程PCB
- 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程
- 终止其所有子进程
- 将该进程拥有的所有资源归还给父进程或操作系统
- 删除PCB
- 引起进程终止的事件
- 正常结束
- 异常结束
- 外界干预
- 撤销原语(就绪态/阻塞态/运行态$\Longrightarrow$ 终止态$\Longrightarrow$ 无)
- 进程的阻塞
- 阻塞原语(运行态$\Longrightarrow$ 阻塞态)
- 找到要阻塞的进程对应的PCB
- ==保护进程运行现场==,将PCB状态信息设置为“阻塞态”,暂时停止进程运行
- 将PCB插入相应事件的等待队列
- 引起进程阻塞的事件
- 需要等待系统分配某种资源
- 需要等待相互合作的其他进程完成工作
- 阻塞原语(运行态$\Longrightarrow$ 阻塞态)
- 进程的唤醒
- 唤醒原语(阻塞态$\Longrightarrow$ 就绪态)
- 在事件等待队列中找到PCB
- 将PCB从等待队列移除,设置为就绪态
- 将PCB插入就绪队列,等待被调度
- 引起进程唤醒的事件
- 等待的事件发生
- 唤醒原语(阻塞态$\Longrightarrow$ 就绪态)
- 进程的切换
- 切换原语(运行态$\Longrightarrow$ 就绪态, 就绪态$\Longrightarrow$ 运行态)
- 将==运行环境信息==存入PCB
- PCB移入相应队列
- 选择另一个进程执行,并更新其PCB
- 根据PCB恢复==新进程所需的运行环境==
- 引起进程切换的事件
- 当前进程时间片到
- 有更高优先级的进程到达
- 当前进程主动阻塞
- 当前进程终止
- 切换原语(运行态$\Longrightarrow$ 就绪态, 就绪态$\Longrightarrow$ 运行态)
- 进程的创建
进程通信
- 共享存储
- 设置一个共享内存区域,并映射到进程的虚拟地址空间
- 要==互斥地访问==共享空间(由通信进程自己负责实现互斥)
- 两种方式
- 基于数据结构(低级):如共享空间里只能放一个长度为10的数组。是一种==低级通信==方式
- 基于存储区的共享(高级):操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种==高级通信==方式
- 消息传递
- 进程间的数据交换以==格式化的消息==为单位
- 进程通过操作系统提供的“发送消息/接收消息”两个==原语==进行数据交换
- 两种方式
- 直接通信方式:消息发送进程要指明接收进程的ID
- 间接通信方式:通过“信箱”间接地通信。因此又称“==信箱通信方式==”
- 管道通信
- 只能采用==半双工通信==
- 如果要实现==双向同时通信==,则需要设置==两个管道==
- 各进程要==互斥==地访问管道
- 当==管道写满==时,==写进程==将==阻塞==,直到读进程将管道中的数据取走,即可唤醒写进程
- 当==管道读空==时,==读进程==将==阻塞==,直到写进程往管道中写入数据,即可环境读进程
- 管道中的数据一旦被读出,就彻底消失
- 一个管道允许多个写进程,一个读进程
线程概念,多线程模型
- 线程的概念
- 线程是一个==基本的CPU执行单位==,也是==程序执行流的最小单位==
- 引入线程之后,进程内的==各线程之间==也可以并发,从而进一步==提升了系统的并发度==,使得一个进程内也可以并发处理各种任务
- 引入线程之后,==进程==只作为==除CPU之外的系统资源的分配单元==
- 线程则作为==处理机的分配单元==
- 引入线程机制后,带来的变化
- 资源分配、调度
- 传统进程机制中,进程是资源分配、调度的基本单位
- 引入线程后,进程是资源分配的基本单位,线程是==调度的基本单位==
- 并发性
- 传统进程机制中,只能进程间并发
- 引入线程后,各线程间也能并发,提升了并发度
- 系统开销
- 传统的进程间并发,需要切换进程的运行环境,系统开销很大
- 线程间并发,如果是同一进程内的线程切换,则不需要切换进程环境,系统开销小
- 引入线程后,并发所带来的系统开销减小
- 资源分配、调度
- 线程的属性
- 线程是处理机调度的单位
- 多CPU计算机中,各个线程可占用不同的CPU
- 每个线程都有一个线程ID、线程控制块TCB
- 线程也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同一进程的不同线程间共享进程的资源
- 由于共享内存地址空间,同一进程间的线程通信甚至无需系统干预
- 同一进程中的线程切换,不会引起进程切换
- 不同进程中的线程切换,会引起进程切换
- 切换同进程内的线程,系统开销很小
- 切换进程,系统开销较大
线程的实现方式,多线程模型
线程的实现方式
- 用户级线程
- 从用户视角能看到的线程,由线程库实现
- 优点:线程管理的系统开销小,效率高
- 缺点:并发度不高。多个线程不可在多核处理机上并行运行
![用户级线程]()
- 内核级线程
- 从操作系统视角看到的线程,由操作系统实现。内核级线程才是处理机分配的单位
- 优点:并发能力强。多线程可在多核处理机上并行执行
- 缺点:线程管理的成本高,开销大
![内核级线程]()
- 组合方式:上述两种方式的结合
- 用户级线程
多线程模型
一对一模型:
![一对一模型]()
- 一个用户级线程映射到一个内核级线程
- 优点:各个线程可分配到多核处理机并行执行,并发度高
- 缺点:线程管理都需要操作系统支持,开销大
多对一模型
![多对一模型]()
- 多个用户级线程映射到一个内核级线程
- 优点:线程管理开销小,效率高
- 缺点:一个线程阻塞会导致整个进程都被阻塞(并发度低)
多对多模型
![多对多模型]()
- n个用户级线程映射到m个内核级线程($n\ge m$)
- 集二者之所长
注意:操作系统只“看得见”内核级线程,因此==只有内核级线程才是处理机分配的单位==
调度的概念、层次
- 基本概念
- 按某种算法选择一个进程将处理机分配给它
- 三个层次
- 高级调度(作业调度):
- 按照某种规则,从后备队列中选择合适的作业将其调入内存,并为其创建进程
- 简单理解:好几个程序需要启动,到底先启动哪个
- 每个作业只调入一次,调出一次
- 作业调入时会创建PCB,调出时才撤销PCB
- 中级调度(内存调度):
- 按照某种规则,从挂起队列中选择合适的进程将其数据调回内存
- 暂时调度外存等待的进程状态为==挂起状态==,被挂起的进程PCB会被组织成==挂起队列==
- 低级调度(进程调度/处理机调度):
- 按照某种规则,从就绪队列中选择一个进程为其分配处理机
- 操作系统中==最基本的一种调度==
- 高级调度(作业调度):
- 三层调度的联系、对比
- 高级调度
- 外存$\Longrightarrow$内存(面向作业)
- 发生频率:最低
- 中级调度
- 外存$\Longrightarrow$内存(面向进程)
- 发生频率:中等
- 低级调度
- 内存$\Longrightarrow$CPU
- 发生频率:最高
- 高级调度
- 补充知识
- 为减轻系统负载,提高资源利用率,暂时不执行的进程会被调到外存从而变为“挂起态”
- 七状态模型:在五状态的基础上加入了“就绪挂起”和“阻塞挂起”两种状态

进程调度的时机,切换与过程,调度方式
- 时机
- 什么时候需要进程调度
- 主动放弃
- 进程正常终止
- 运行过程中发生异常而终止
- 主动阻塞(如 等待I/O)
- 被动放弃
- 分给进程的时间片用完
- 有更紧急的事情需要处理(如 I/O中断)
- 有更高优先级的进程进入就绪队列
- 主动放弃
- 什么时候不能进行进程调度
- 在处理中断的过程中
- 进程在操作系统内核程序临界区中
- 原子操作过程中(原语)
- 临界资源:一个时间段内只允许一个进程使用的资源。各进程需要==互斥地==访问临界资源
- 临界区:访问临界资源的那段代码
- 什么时候需要进程调度
- 切换与过程
- 狭义的“调度”和“切换”的区别
- 狭义的进程调度指的是从就绪队列中==选中一个要运行的程序==(这个进程可以是刚刚被暂停执行的进程,也可能是==另一个进程==,后一种情况就需要==进程切换==)
- 进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程
- 广义的进程调度包含了选择一个进程和进程切换两个步骤
- 切换过程
- 对原来运行进程各种数据的保存
- 对新的进程各种数据的恢复
- 重要结论:进程调度、切换是有代价的,并不是调度越频繁,并发度就越高
- 狭义的“调度”和“切换”的区别
- 方式
- 非剥夺调度方式(非抢占式)
- 只能由当前运行的进程主动放弃CPU
- 剥夺调度方式(抢占式)
- 可由操作系统剥夺当前进程的CPU使用权
- 非剥夺调度方式(非抢占式)
调度器、闲逛进程
- 什么事件会触发调度程序?
- 创建新进程
- 进程退出
- 运行进程堵塞
- I/O中断发生
- 非抢占式调度策略:只有运行进程阻塞或退出才触发调度程序工作
- 抢占式调度策略:每个时钟中断或k个时钟中断会触发调度程序工作
- 闲逛进程:没有其他就绪进程时,运行闲逛进程(idle)
调度的目标
CPU利用率
- $利用率=\frac{\text{忙碌的时间}}{\text{总时间}}$
系统吞吐量
- $系统吞吐量 = \frac{\text{总共完成了多少道作业}}{\text{总共花了多少时间}}$
周转时间
- 周转时间 = 作业完成时间-作业提交时间
- $平均周转时间=\frac{\text{各作业周转时间之和}}{\text{作业数}}$
- $带权周转时间=\frac{\text{作业周转时间}}{\text{作业实际运行时间}}$
- $平均带权周转时间=\frac{\text{各作业带权周转之和}}{\text{作业数}}$
等待时间
- 进程/作业等待被服务的时间之和
- 平均等待时间即各个进程/作业等待时间的平均值
响应时间
- 从用户提交请求到首次产生响应所用的时间
调度算法
| 算法 | 可抢占? | 优点 | 缺点 | 考虑到等待时间&运行时间? | 会导致饥饿? |
|---|---|---|---|---|---|
| 先来先服务FCFS | 非抢占式 | 公平;实现简单 | 对短作业不利 | 等待时间✅运行时间❌ | 不会 |
| 短作业优先SJF/SPF | 默认为非抢占式,也有抢占式版本SRTN | “最短的”平均等待/周转时间 | 对长作业不利,可能导致饥饿;难以做到真正的短作业优先 | 等待时间❌运行时间✅ | 会 |
| 高响应比优先HRRN | 非抢占式 | 上述两种算法的权衡折中,综合考虑的等待时间和运行时间 | 等待时间✅运行时间✅ | 不会 | |
| 时间片轮转 | 抢占式 | 公平,适用于分时系统 | 频繁切换有开销,不区分优先级 | 不会 | |
| 优先级调度 | 有抢占式,也有非抢占式 | 区分优先级,适用于实时系统 | 可能导致饥饿 | 会 | |
| 多级反馈队列 | 抢占式 | 平衡优秀 | 可能导致饥饿 | 会 |
$响应比=\frac{\text{等待时间+要求服务时间}}{\text{要求服务时间}}$
同步与互斥的基本概念
- 进程同步
- 并发性带来了异步性,有时需要通过进程同步解决这种异步问题
- 有的进程之间需要相互配合地完成工作,各进程的工作推进需要遵循一定的先后顺序
- 进程互斥
- 对临界资源的访问,需要互斥的进行,即同一时间段内只能允许一个进程访问资源
- 四个部分
- 进入区
- 检查是否可进入临界区,若可进入,需要“上锁”
- 临界区
- 访问临界资源的那段代码
- 退出区
- 负责“解锁”
- 剩余区
- 其余代码部分
- 进入区
- 需要遵循的原则
- 空闲让进
- 临界区空闲时,应允许一个进程访问
- 忙则等待
- 临界区正在被访问时,其他试图访问的进程需要等待
- 有限等待
- 要在有限时间内进入临界区,保证不会饥饿
- 让权等待
- 进不了临界区的进程,要释放处理机,防止忙等
- 空闲让进
进程互斥的软件实现方法
单标志法
- 在进入区只做“检查”,不“上锁”
- 在退出区把临界区的使用权转交给另一个进程
- 主要问题:不遵循“空闲让进”原则
双标志先检查
- 在进入区先“检查”后“上锁”,退出区“解锁”
- 主要问题:不遵循“忙则等待”原则
双标志后检查
- 在进入区先“加锁”后“检查”,退出区“解锁”
- 主要问题:不遵循“空闲让进,有限等待”原则,可能导致“饥饿”
Peterson算法
- 在进入去“主动争取-主动谦让-检查对方是否想进、己方是否谦让”
- 主要问题:不遵循“让权等待”原则,会发生“忙等”
进程互斥的硬件实现方法
- 中断屏蔽方法
- 优点:简单高效
- 缺点
- 只适用于单处理机
- 只适用于操作系统内核程序
- TestAndSet(TS指令/TSL指令)
- 是用硬件实现的,执行的过程不允许被中断,只能一气呵成
- 优点
- 实现简单
- 适用于多处理机环境
- 缺点:不满足“让权等待”
1 | // bool变量lock表示当前临界区是否被加锁 |
- Swap指令(XCHG指令)
- 是用硬件实现的,执行的过程不允许被中断,只能一气呵成
- 逻辑上和TS指令类似
1 | // Swap指令的作用是交换两个变量的值 |
信号量机制
- 整型信号量
- 用一个整数型变量作为信号量,数值表示某种资源数
- 整型信号量与普通整型变量的区别:对信号量只能执行
初始化,P,V三种操作 - 整型信号量存在的问题:不满足让权等待原则
- 记录型信号量
S.value表示某种资源数,S.L指向等待该资源的队列P操作中,一定是先S.value--,之后可能需要执行block原语V操作中,一定是先S.value++,之后可能需要执行wakeup原语- 可以用记录型信号量实现系统资源的“申请”和“释放”
- 可以用记录型信号量实现进程互斥、进程同步
用信号量机制实现进程互斥、同步、前驱关系
- 实现进程互斥
- 分析问题,确定临界区
- 设置互斥信号量,初值为1
- 临界区之前对信号量执行P操作
- 临界区之后对信号量执行V操作
- 实现进程同步
- 分析问题,找出哪里需要实现“一前一后”的同步关系
- 设置同步信号量,初始值为0
- 在“前操作”之后执行V操作
- 在“后操作”之前执行P操作
- 实现进程的前驱关系
- 分析问题,画出前驱图,把每一对前驱关系都看成一个同步问题
- 为每一对前驱关系设置同步信号量,初值为0
- 在每个“前操作”之后执行V操作
- 在每个“后操作”之前执行P操作
生产者、消费者问题
问题描述
系统中由一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待
缓冲区是临界资源,各进程必须互斥地访问
问题分析
- 设置信号量
1 | semaphore mutex = 1; // 互斥信号量,实现对缓冲区的互斥访问 |
- 生产者
1 | producer () { |
- 消费者
1 | consumer () { |
注意
实现互斥的P操作一定要在实现同步的P操作之后
两个V操作顺序可以交换
多生产者-多消费者
问题描述
桌子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。用PV操作实现上述过程

问题分析
- 互斥关系:(mutex = 1)
- 对缓冲区(盘子)的访问要互斥地进行
- 同步关系(一前一后)
- 父亲将苹果放入盘子后,女儿才能取苹果
- 母亲将橘子放入盘子后,儿子才能取橘子
- 只有盘子为空时,父亲或母亲才能放入水果

- 信号量
1 | semaphore metux = 1; // 实现互斥访问盘子 |
- 父亲
1 | dad () { |
- 母亲
1 | mom () { |
- 女儿
1 | daughter () { |
- 儿子
1 | son() { |
注意
本题缓冲区大小为1,在任何时刻,orange、apple、plate三个同步信号量中最多只有一个为1,因此可以不用semaphore metux = 1;
如果盘子容量为2,不可删除semaphore metux = 1;
也即,如果缓冲区大小大于1,就必须专门设置一个互斥信号量mutex来保证互斥访问缓冲区
读者-写者问题
问题描述
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件进行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出

问题分析
- 两类进程:写进程、读进程
- 互斥关系:写进程-写进程、写进程-读进程
- 信号量
1 | semaphore rw = 1; // 用于实现对共享文件的互斥访问 |
- 写者
1 | writer () { |
- 读者
1 | reader () { |
哲学家进餐问题
问题描述
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下子继续思考。

问题分析
- 可以对哲学家进程施加一些限制条件,比如最多允许四个哲学家同时进餐
- 要求奇数号哲学家先拿左边的筷子,然后再拿右边的筷子,而偶数号哲学家刚好相反
- 仅当一个哲学家左右两支筷子都可用时才允许他抓起筷子
1 | semaphore chopstick[5] = {1, 1, 1, 1, 1}; |
管程
- 为什么要引入管程
- 解决信号量机制编程麻烦、易出错的问题
- 组成
- 共享数据结构
- 对数据结构初始化的语句
- 一组用来访问数据结构的过程(函数)
- 基本特征
- 各外部进程/线程只能通过管程提供的特定“入口”才能访问共享数据
- 每次仅允许一个进程在管城内执行某个内部过程
- 补充
- 各进程必须互斥访问管程的特性是由编译器实现的
- 可在管程中设置条件变量及等待/唤醒操作以解决同步问题
死锁的概念
- 什么是死锁
- 各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进
- 死锁、饥饿、死循环的区别
- 死锁:至少是两个进程一起死锁,死锁进程处于阻塞态
- 饥饿:可以只有一个进程饥饿,饥饿进程可能阻塞也可能就绪
- 死循环:可能只有一个进程发生死循环,死循环的进程可上处理机
- 死锁和饥饿是==操作系统==要解决的问题,死循环是==程序员==要解决的问题
- 死锁产生的必要条件
- 互斥条件
- 对必须互斥使用的资源的争夺才会导致死锁
- 不剥夺条件
- 进程保持的资源只能主动释放,不可强行剥夺
- 请求和保持条件
- 保持着某些资源不放的同时,请求别的资源
- 循环等待条件
- 存在一种进程资源的循环等待链
- 循环等待未必死锁,死锁一定有循环等待
- 互斥条件
- 什么时候会发生死锁
- 对不可剥夺资源的不合理分配,可能导致死锁
- 死锁的处理策略
- 预防死锁:破坏死锁产生的四个必要条件
- 避免死锁:避免系统进入不安全状态(银行家算法)
- 死锁的检测和解除:允许死锁发生,系统负责检测出死锁并解除
死锁的处理策略——预防死锁
- 破坏互斥条件
- 将临界资源改造为可共享使用的资源(如SPOOLing技术)
- 缺点:可行性不高,很多时候无法破坏互斥条件
- 破坏不剥夺条件
- 方案一:申请的资源得不到满足时,立即释放拥有的所有资源
- 方案二:申请的资源被其他进程占用时,由操作系统协助剥夺(考虑优先级)
- 缺点:
- 实现复杂
- 剥夺资源可能导致部分工作失效
- 反复申请和释放导致系统开销大
- 可能导致饥饿
- 破坏请求和保持条件
- 运行前分配好所有需要的资源,之后一直保持
- 缺点
- 资源利用率低
- 可能导致饥饿
- 破坏循环等待条件
- 给资源编号,必须按编号从大到小的顺序申请资源
- 缺点
- 不方便增加新设备
- 会导致资源浪费
- 用户编程麻烦
死锁的处理策略——避免死锁
什么是安全序列
安全序列,指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要找到一个安全序列,系统就是==安全状态==
安全序列可能有多个
什么是系统的不安全状态,与死锁有何联系
- 如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了==不安全状态==
- 如果系统处于安全状态,就==一定不会发生死锁==
- 如果系统处于不安全状态,就==可能发生死锁==
如何避免系统进入不安全状态——银行家算法
核心思想:在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待
死锁的处理策略——死锁的检测
如何检测
- 数据结构:资源分配图
- 两种结点
- 进程结点(图中蓝色结点)
- 资源结点(图中绿色结点)
- 两种边
- $进程结点\Longrightarrow 资源结点$(请求边,图中蓝色边)
- $资源结点\Longrightarrow 进程结点$(分配边,图中绿色边)
- 两种结点
![资源分配图]()
- 死锁检测算法
- 依次消除与不阻塞边进程相连的边,直到无边可消
- 死锁定理:若资源分配图是不可完全简化的,说明发生了死锁
- 如何解除
- 资源剥夺法。挂起(暂时放到外存上)某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但是应防止被挂起的进程长时间得不到资源而饥饿。
- 撤销进程法(或称终止进程法)。强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。这种方式的优点是==实现简单==,但所付出的==代价可能会很大==。因为有些进程可能已经运行了很长时间,已经接近结束了,旦被终止可谓功亏一篑,以后还得从头再来。
- 进程回退法。让一个或多个死锁进程回退到足以避免死锁的地步。这就要求系统要记录进程的历史信息,设置还原点。
- 数据结构:资源分配图






