导图社区 进程管理
进一步了解操作系统之进程管理,可以点击下图查看。
编辑于2020-09-25 17:15:32第二章 进程管理
2.1进程与线程
2.1.1 进程的概念和特征
1.进程的概念
定义
1)进程是程序的一次执行过程
2)进程是一个程序及其数据在处理机上顺序执行时所发生的活动
3)进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
专门的数据结构
进程控制块(PCB)
PCB是进程存在的唯一标志!
进程映像(进程实体)
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位
程序段
数据段
PCB
2.进程的特征
1)动态性
动态性是进程最基本的特征
进程是程序的一次执行过程,是动态地产生、变化和消亡的
2)并发性
内存中有多个进程实体,各进程可并发执行
3)独立性
进程是能独立运行、独立获得资源、独立接受调度的基本单位
4)异步性
异步性会导致并发程序执行结果的不确定性
各进程按各自独立的、不可预知的速度向前推进,操作系统要提供“进程同步机制”来解决异步问题
5)结构性
每个进程都会配置一个PCB。结构上看,进程由程序段、数据段、PCB组成
2.1.2 进程的状态与转换
状态
运行状态
CPU✔其他所需资源✔
就绪状态
CPU❌其他所需资源✔
阻塞状态
CPU❌其他所需资源❌
创建状态
操作系统为是新进程分配资源、创建PCB
终止状态
操作系统回收进程的资源、撤销PCB
状态间的转换
就绪态—>运行态
进程被调度
运行态—>就绪态
时间片到,或CPU被其他高优先级的进程抢占
运行态—>阻塞态
等待系统资源分配,或等待或某事件发生(主动行为)
阻塞态—>就绪态
资源分配到位,等待的事件发生(被动行为)
创建态—>就绪态
系统完成创建进程相关的工作
运行态—>终止态
进程运行结束,或运行过程中遇到不可修复的错误
五状态模型
状态(详细版)
三种基本状态
运行态(Running)
占有CPU,并在CPU上运行
就绪态(Ready)
已经具备运行条件,但由于没有空闲CPU,而暂时不能运行
进程已经拥有除了处理及之外所有需要的资源,一旦获得处理机,即可立即进入运行态开始运行。即:万事俱备,只欠CPU
阻塞态(Waiting/Blocked,又称:等待态)
因等待某一事件而暂时不能运行
如:等待操作系统分配打印机、等待读磁盘操作的结果。CPU是计算机中最昂贵的部件,为了提高CPU的利用率,需要先将其他进程需要的资源分配到位,才能得到CPU的服务
另外两种状态
创建态(New,又称:新建态)
进程正在被创建,操作系统为进程分配资源、初始化PCB
终止态(Terminated,又称:结束态)
进程正在从系统中撤销,操作系统会回收进程拥有的资源、撤销PCB
2.1.3 进程控制
基本概念
什么是进程控制?
进程控制就是要实现进程状态的转换
如何实现进程控制
进程控制用原语实现
原语用关/开中断来实现
原语是一种特殊的程序
原语的执行必须一气呵成,不可中断
进程控制相关的原语
1.进程的创建
创建原语
操作系统创建一个进程时使用的原语
1)申请空白PCB
2)为新进程分配所需资源
3)初始化PCB
4)将PCB插入就绪队列
创建态→就绪态
引起进程创建的事件
用户登录
分时系统中,用户登录成功,系统会其建立一个新的进程
作业调度
多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程
提供服务
用户向操作系统提出某些请求时,会新建一个进程处理该请求
应用请求
由用户进程主动请求创建一个子进程
2.进程的终止
撤销原语
就绪态/阻塞态/运行态→终止态→无
1)从PCB集合中找到终止进程的PCB
2)若进程正在运行,立即剥夺CPU,将CPU分配给其他进程
3)终止其所有子进程
进程间的关系是树形结构
4)将该进程拥有的所有资源归还给父进程或操作系统
5)删除PCB
引起进程终止的事件
①正常结束
进程自己请求终止(exit系统调用)
②异常结束
整数c除以0、非法使用特权指令,然后被操作系统强行杀掉
③外界干预
Ctrl+Alt+delete,用户选择杀掉进程
3.进程的阻塞和唤醒
阻塞原语、唤醒原语必须成对使用
进程的阻塞
阻塞原语
运行态→阻塞态
1)找到要阻塞的进程对应的PCB
2)保护进程运行现场,将PCB状态信息设置为“阻塞态”,暂时停止进程运行
3)将PCB插入相应事件的等待队列
引起进程阻塞的事件
需要等待系统分配某种资源
需要等待相互合作的其他进程完成工作
进程的唤醒
唤醒原语
阻塞态→就绪态
1)在事件等待队列中找到PCB
2)将PCB从等待队列移除,设置进程为就绪态
3)将PCB插入就绪队列,等待被调度
引起进程唤醒的事件
等待的事件发生
因何事阻塞,就应由何事唤醒
4.进程的切换
切换原语
运行态→就绪态 就绪态→运行态
1)将运行环境信息存入PCB
进程上下文(Context)
2)PCB移入相应队列
3)选择另一个进程执行,并更新其PCB
4)根据PCB恢复新进程所需的运行环境
引起进程切换的事件
当前进程时间片到
有更高优先级的进程到达
当前进程主动阻塞
当前进程终止
三件事
1.更新PCB中的信息
修改进程状态(state) 保存/恢复运行环境
2.将PCB插入合适的队列
3.分配/回收资源
2.1.4 进程的组织
1.进程控制块(PCB)
PCB是给操作系统用的,是进程存在的唯一标志
1)进程描述信息
进程标识符PID
用户标识符UID
标识符
2)进程控制和管理信息
CPU、磁盘、网络流量使用情况统计...
进程当前状态:就绪态/阻塞态/运行态
进程优先级
信息
3)资源分配清单
正在使用哪些文件
正在使用哪些区域
正在使用哪些I/O设备
文件、区域、I/O设备
4)处理机相关信息
如PSW、PC等等各种寄存器的值(用于实现进程切换)
进程切换
2.程序段
程序的代码(指令序列)
代码
3.数据段
运行过程中产生的各种数据(如:程序中定义的变量)
程序段和数据段是给进程自己用的,与进程自身的运行逻辑有关
数据
PCB的组织方式
链式方式
按照进程状态将PCB分为多个队列
操作系统持有指向各个队列的指针
索引方式
根据进程状态的不同,建立几张索引表
操作系统持有指向各个索引表的指针
2.1.5 进程通信
这里的是高级通信方式,PV操作是低级通信方式
1.共享存储
设置一个共享空间
要互斥地访问共享空间
两种方式
基于数据结构(低级)
基于存储区的共享(高级)
2.消息传递
传递结构化的消息(消息头/消息体)
系统提供“发送/接收原语”
两种方式
1)直接通信方式
消息直接挂到接收方的消息队列里
2)间接(信箱)通信方式
消息先发到中间体(信箱)
3.管道通信
设置一个特殊的共享文件(管道),其实就是一个缓冲区
一个管道只能实现半双工通信
实现双向同时通信建立两个管道
各进程要互斥访问管道
写满时,不能再写。读空时,不能读
没写满,不能读。没读空,不能写
2.1.6 线程的概念和多线程模型
1.线程的基本概念
什么是线程,为什么要引入线程?
线程是一个基本的CPU执行单元,也是程序执行流的最小单位
引入线程可以提升系统的并发度
引入线程后,线程成为了程序执行流的最小单位
引入线程后,进程只作为除CPU之外的系统资源的分配单元(如打印机、内存地址空间等都是分配给进程的)
2.线程与进程的比较
引入线程机制后,有什么变化?
带来的变化
资源分配、调度
传统进程机制中,进程就是资源分配、调度的基本单位
引入线程后,进程是资源分配的基本单位,线程是调度的基本单位
并发性
传统进程机制中,只能进程间并发
引入线程机制后,各线程间也能并发,提升了并发度
系统开销
传统的进程间并发,需要切换进程的运行环境,系统开销很大
线程间并发,如果是同一进程内的线程切换,则不需要切换进程环境,系统开销小
引入线程后,并发所带来的系统开销减小
3.线程的属性
线程是处理机调度的单位
多CPU计算机中,各个线程可占用不同的CPU
每个线程都有一个线程ID、线程控制块(TCB)
线程也有就绪、阻塞、运行三种基本状态
线程几乎不拥有系统资源
同一进程的不同线程间共享进程的资源
由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预
同一进程中的线程切换,不会引起进程切换
不同进程中的线程切换,会引起进程切换
切换同进程内的线程,系统开销很小
切换进程,系统开销大
4.线程的实现方式
用户级线程
从用户视角能看到的线程,由线程库实现
优点
线程切换都在用户态下完成,不需要切换到核心态,线程管理的系统开销小,效率高
缺点
当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可以在多核处理机上并行运行
内核级线程
从操作系统视角看到的线程,由操作系统实现 (内核级线程才是处理机分配的单位)
优点
当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行
缺点
一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大
5.多线程模型
1)多对一模型
多个用户级线程映射到一个内核级线程
优点
线程管理开销小效率高
缺点
一个线程阻塞会导致整个进程都被阻塞(并发度低)
2)一对一模型
一个用户级线程映射到一个内核级线程
优点
各个线程可分配到多核处理机并行执行,并发度高
缺点
线程管理需要操作系统支持,开销大
3)多对多模型
n个用户级线程映射到m个内核级线程(n≥m)
集二者之所长
2.2处理机调度
2.2.1 调度的概念
基本概念
按某种算法选择一个进程将处理机分配给它
三个层次
高级调度(作业调度)
按照某种规则,从后备队列中选择合适的作业将其调入内存,并为其创建进程
中级调度(内存调度)
按照某种规则,从挂起队列中选择合适的进程将其数据调回内存
暂时调到外存等待的进程状态为挂起状态
被挂起的进程PCB会被组织成挂起队列
低级调度(进程调度)
按照某种规则,从就绪队列中选择一个进程为其分配处理机
调度算法要研究的问题
最基本的一种调度
三层调度的联系、对比
高级调度
外存—>内存(面向作业)
发生频率:最低
无→创建态→就绪态
中级调度
外存—>内存(面向进程)
发生频率:中等
挂起态→就绪态 (阻塞挂起→阻塞态) (就绪挂起→就绪态)
低级调度
内存—>CPU
发生频率:最高
就绪态→运行态
补充知识
为减轻系统负载,提高资源利用率,暂时不执行的进程会被调到外存从而变为“挂起态”
七状态模型
在五状态模型的基础上加入了“就绪挂起”和“阻塞挂起”两种状态
为什么要进行处理机调度?
合理的处理计算机的软件硬件资源
2.2.2 调度的时机、切换与过程
进程调度的时机
什么时候需要进程调度?
主动放弃
进程正常终止
运行过程中发生异常而终止
主动阻塞(如 等待I/O)
被动放弃
分给进程的时间片用完
有更紧急的事情需要处理(如I/O中断)
有更高优先级的进程进入就绪队列
什么时候不能进行进程调度?
在处理中断的过程中
进程在操作系统内核程序临界区中
内核程序临界区一般是用来访问某种内核数据结构的,比如进程的就绪队列(由各就绪进程的PCB组成)
就绪队列被上锁,进行进程调度需要访问就绪队列,此时如果进行进程调度,则无法顺利完成
进程在访问普通临界区时可以进行进程调度与切换
打印机资源
临界资源:一个时间段内只允许一个进程使用的资源。各进程需要互斥地访问临界资源。
临界区:访问临界资源的那段代码
原子操作过程中(原语)
如之前讲过的修改PCB中进程状态标志,并把PCB放到相应队列
进程调度的切换与过程
狭义的“调度”和“切换”的区别
狭义的进程调度指的是从就绪队列中选中一个要运行的进程。(这个进程可以是刚刚被暂停执行的进程,也可能是另一个进程,后一种情况就需要进程切换)
进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程。
切换过程
1.对原来运行进程各种数据的保存
2.对新进程的各种数据的恢复
如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块
重要结论
进程调度、切换是有代价的,并不是调度越频繁,并发度就越高
2.2.3 进程调度方式
非剥夺调度方式(非抢占式)
适用于早期的批处理系统
只能由当前运行的进程主动放弃CPU
剥夺调度方式(抢占式)
适用于分时操作系统、实时操作系统
可由操作系统剥夺当前进程的CPU使用权
2.2.4 调度的基本准则
CPU利用率
也有题目会让我们计算某设备的利用率
系统吞吐量
周转时间
越小越好
必然≥1,越小越好
等待时间
进程/作业 等待被服务的时间之和
平均等待时间即各个 进程/作业 等待时间的平均值
响应时间
从用户提交请求到首次产生响应所用的时间
2.2.5 典型的调度算法
1.先来先服务(FCFS)
1.算法思想
主要从“公平”的角度考虑(类似于我们生活中排队买东西的例子)
2.算法规则
按照作业/进程到达的先后顺序进行服务
3.用于作业/进程调度
用于作业调度时,考虑的是哪个作业先到达后备队列
用于进程调度时,考虑的是哪个进程先到达就绪队列
4.是否可抢占
非抢占式的算法
5.优缺点
优点
公平、算法实现简单
缺点
排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好
即,FCFS算法对长作业有利,对短作业不利(Eg:排队买奶茶…)
有利于CPU繁忙型作业,不利于I/O繁忙型作业
6.是否会导致饥饿
某进程/作业长期得不到服务
不会
2.短作业优先(SJF)
1.算法思想
追求最少的平均等待时间,最少的平均周转时间、最少的平均带权周转时间
2.算法规则
当前已经到达的且运行时间最短的作业/进程优先得到服务(所谓“最短“,是指要求服务时间最短)
3.用于作业/进程调度
即可用于作业调度,也可用于进程调度
用于进程调度时称为”短进程优先(SPF,Shortest Process First)算法“
4.是否可抢占
SJF和SPF是非抢占式的算法。
但是也有抢占式的版本——最短剩余时间优先算法(SRTN,Shortest Remaining Time Next)
最短剩余时间优先算法:每当有进程加入就绪队列改变时就需要调度,如果新到达的进程剩余时间比当前运行的进程剩余时间更短,则由新进程抢占处理机,当前运行进程重新回到就绪队列。另外,当一个进程完成时也需要调度
5.优缺点
优点
”最短的“平均等待时间、平均周转时间
缺点
不公平。对短作业有利,对长作业不利。可能产生饥饿现象
另外,作业/进程的运行时间是由用户提供的,并不一定真实,不一定能做到真正的短作业优先
6.是否会导致饥饿
会
如果源源不断地有短作业/进程到来,可能使长作业/进程长时间得不到服务,产生”饥饿“现象。如果一直得不到服务,则称为”饿死“
注意
1.如果题目中未特别说明,所提到的“短作业/进程优先算法”默认是非抢占式的
2.很多书上都会说“SJF调度算法的平均等待时间、平均周转时间最少”
严格来说,这个表述是错误的,不严谨的。之前的例子表明,最短剩余时间优先算法得到的平均等待寸间、平均周转时间还要更少
应该加上一个条件“在所有进程同时可运行时,采用SF调度算法的平均等待时间、平均周转时间最少或者说“在所有进程都几乎同时到达时,采用SF调度算法的平均等待时间、平均周转时间最少
如果不加上述前提条件,则应该说“抢占式的短作业/进程优先调度算法(最短剩余时间优先,SRNT 算法)的平均等待时间、平均周转时间最少”
3.虽然严格来说,SJF的平均等待时间、平均周转时间并不一定最少,但相比于其他算法(如FCFS),SJF依然可以获得较少的平均等待时间、平均周转时间
4.如果选择题中遇到“SJF算法的平均等待时间、平均周转时间最少”的选项,那最好判断其他选项是有很明显的错误,如果没有更合适的选项,那也应该选择该选项
3.高响应比优先(HRRN)
1.算法思想
要综合考虑作业/进程的等待时间和要求服务的时间
2.算法规则
在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务
响应比 ≥ 1
3.用于作业/进程调度
即可用于作业调度,也可用于进程调度
4.是否可抢占
非抢占式的算法
因此只有当前运行的作业/进程主动放弃处理机时,才需要调度,才需要计算响应比
5.优缺点
综合考虑了等待时间和运行时间(要求服务时间)
等待时间相同时,要求服务时间短的优先(SJF的优点)
要求服务时间相同时,等待时间长的优先(FCFS的优点)
对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题
6.是否会导致饥饿
不会
适用于早期的批处理系统, 不关心“响应时间”,也不区分任务的紧急程度
4.时间片轮转调度算法(RR)
1.算法思想
公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应
2.算法规则
按照各进程到达就绪队列的顺序,轮流让各个进程执行一个时间片(如100ms)。
若进程未在一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队
3.用于作业/进程调度
用于进程调度(只有作业放入了内存,建立了相应的进程后,才能被分配处理机时间片)
4.是否可抢占
若进程未能在时间片内运行完,将被强行剥夺处理机使用权
因此时间片轮转调度算法属于抢占式的算法
由时钟装置发出时钟中断来通知CPU时间片已到
5.优缺点
优点
公平,响应快,适用于分时操作系统
缺点
由于高频率的进程切换,因此有一定开销
不区分任务的紧急程度
6.是否会导致饥饿
不会
补充
时间片太大或太小分别有什么影响?
太大
如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法退化为先来先服务调度算法,并且会增大进程响应时间。因此时间片不能太大
太小
另一方面,进程调度、切换是有时间代价的(保存、恢复运行环境),因此如果时间片太小,会导致进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少。可见时间片也不能太小
一般来说,设计时间片时 要让切换进程的开销占比不超过1%
5.优先级调度算法
1.算法思想
随着计算机的发展,特别是实时操作系统的出现,越来越多的应用场景需要根据任务的紧急程度来决定处理顺序
2.算法规则
每个作业/进程都有各自的优先级,调度时选择优先级最高的作业/进程
3.用于作业/进程调度
既可用于作业调度,也可用于进程调度
甚至,还会用于在之后会学习的I/O调度中
4.是否可抢占
抢占式、非抢占式都有
做题时的区别在于
非抢占式只需在进程主动放弃处理机时进行调度即可
而抢占式还需在就绪队列变化时,检查是否会发生抢占
5.优缺点
优点
用优先级区分紧急程度、重要程度,适用于实时操作系统。可灵活地调整对各种作业/进程的偏好程度
缺点
若源源不断地有高优先级进程到来,则可能导饥饿
6.是否会导致饥饿
会
补充
就绪队列未必只有一个,可以按照不同优先级来组织。另外,也可以把优先级高的进程排在更靠近队头的位置
根据优先级是否可以动态改变,可将优先级分为静态优先级和动态优先级两种。
静态优先级:创建进程时确定,之后一直不变。
动态优先级:创建进程时有一个初始值,之后会根据情况动态地调整优先级。
如何合理地设置各类进程的优先级?
通常:系统进程优先级高于用户进程 前台进程优先级高于后台进程
操作系统更偏好I/O型进程(或称I/O繁忙型进程)
I/O设备和CPU可以并行工作。如果优先让I/O繁忙型进程优先运行的话,则越有可能让I/O设备尽早地投入工作,则资源利用率、系统呑吐量都会得到提升
注:与I/O型进程相对的是计算型进程(或称CPU繁忙型进程)
如果采用的是动态优先级,什么时候应该调整?
可以从追求公平、提升资源利用率等角度考虑
如果某进程在就绪队列中等待了很长时间,则可以适当提升其优先级
如果某进程占用处理机运行了很长时间,则可适当降低其优先级
如果发现一个进程频繁地进行I/O操作,则可适当提升其优先级
6.多级反馈队列调度算法
1.算法思想
对其他调度算法的折中权衡
2.算法规则
1.设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
2. 新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经在最下级的队列,则重新放回该队列队尾
3.只有第k级队列为空时,才会为k+1级队头的进程分配时间片
3.用于作业/进程调度
用于进程调度
4.是否可抢占
抢占式的算法
在k级队列的进程运行过程中,若更上级的队列(1~k-1级)中进入了一个新进程,则由于新进程处于优先级更高的认列中,因此新进程会抢占处理机,原来运行的进程放回k级队列
5.优缺点
对各类型进程相対公平(FCFS的优点);
每个新到达的进程都可以很快就得到响应(RR的优点);
短进程只用较少的时间就可完成(SPF的优点);
不必实现估计进程的运行时间(避免用户作假);
可灵活地调整对各类进程的偏好程度,比如CPU密集型进程、I/O密集型进程(拓展:可以将因I/O而阻塞的进程重新放回原队列,这样I/O型进程就可以保持较高优先级)
6.是否会导致饥饿
会
适用于交互式系统
7.总览
2.3 进程同步
2.3.1 进程同步的基本概念
1.临界资源
一个时间段内只允许一个进程使用的资源。各进程需要互斥地访问临界资源
四个部分
进入区
检查是否可以进入临界区,若可进入,需要“上锁”
临界区
访问临界资源的那段代码
也可称为“临界段”
退出区
负责“解锁”
剩余区
其余代码部分
2.同步
并发性帯来了异步性,有时需要通过进程同步解决这种异步问题
有的进程之间需要相互配合地完成工作,各进程的工作推进需要遵循一定的先后顺序
同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作
3.互斥
概念
对临界资源的访问,需要互斥的进行。同一时间段内只能允许一个进程访问该资源
亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
需要遵循的原则
空闲让进
临界区空闲时,应允许一个进程访问
忙则等待
临界区正在被访问时,其他试图访问的进程需要等待
有限等待
要在有限时间内进入临界区,保证不会饥饿
让权等待
进不了临界区的进程,要释放处理机,防止忙等
2.3.2 实现临界资源区互斥的基本方法
1.软件实现方法
单标志法
在进入区只做"检查",不"上锁"
在退出区把临界区的使用权转交给另一个进程 (相当于在退出区既给另一进程"解锁",又给自己"上锁")
用turn变量表示谦让
主要问题
不遵循"空闲让进"原则
双标志先检查
在进入区先"检查"后"上锁",退出区"解锁"
用flag数组表示进入意愿
主要问题
不遵循"忙则等待"原则
双标志后检查
在进入区先"加锁"后"检查",退出区"解锁"
用flag数组表示进入意愿
主要问题
不遵循"空闲让进、有限等待"原则,可能导致"饥饿"
Peterson算法
在进入区"1.主动争取—2.主动谦让—3.检查对方是否想进、己方是否谦让"
结合turn和flag数组
主要问题
不遵循"让权等待"原则,会发生"忙等"
2.硬件实现方法
1.中断屏蔽方法
使用“开/关中断”指令实现
在某进程开始访问临界区到结束访问为止都不允许被中断,也就不能发生进程切換,因此也不可能发生两个同时访问临界区的情况
优点
简单高效
缺点
只适用于单处理机;只适用于操作系统內核进程,不适用于用户进程(因为开/关中断指令只能运行在内核态,这组指令如果能让用户随意使用会很危险)
不适用于多处理机
2.TestAndSet(Lock)(TS指令/TSL指令)
TSL指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成
old记录是否已被上锁; 再将lock设为true; 检查临界区是否已被上锁 (若已上锁,则循环重复前几步)
优点
实现简单;适用于多处理机环境;
缺点
不满足"让权等待",从而导致“忙等”
3.Swap指令(XCHG指令、Exchange指令)
用硬件实现的,执行的过程不允许被中断,只能一气呵成
优点
实现简单;适用于多处理机环境;
缺点
不满足"让权等待",从而导致“忙等”
2.3.3 信号量
概念
信号量
一个变量(可以是一个整数,也可以是更复杂的记录型变量),表示系统种某种资源的数量
一对原语
wait(S)——P操作
signal(S)——V操作
1.整型信号量
用一个整数型的变量作为信号量,数值表示某种资源数
整型信号量与普通整型变量的区别
对信号量只能执行初始化、P、V三种操作
整型信号量存在的问题
不满足“让权等待”原则,会发生“忙等”
2.记录型信号量
S.value表示某种资源数,S.L指向等待该资源的队列
P操作中,一定是先S.value--,之后可能需要执行block原语
V操作中,一定是先S.value++,之后可能需要执行wakeup原语
注意:要能够自己推断在什么条件下需要执行 block或 wakeup
可以用记录型信号量实现系统资源的"申请"和"释放"
可以用记录型信号量实现进程互斥、进程同步
代码描述
记录型信号量
在考研题目中wait(S) 、signal(S) 也可以记为 P(S) 、V(S)这对原语可用于实现系统资源的“申请”和“释放”
S.value 的初值表示系统中某种资源的数目
wait(S)原语

对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此需要执行S. value-,表示资源数减1,
当S. value<0时表示该类资源已分配完毕,因此进程应调用 block原语进行自我阻塞(当前运行的进程从运行态→阻塞态)
主动放弃处理机,并插入该类资源的等待队列S.L中。可见,该机制遵循了“让权等待”原则,不会出现“忙等”现象。
signal(S)原语

对信号量S的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示资源数加1,
若加1后仍是S.value<=0,表示依然有进程在等待该类资源,因此应调用wakeup原语唤醒等待队列中的第一个进程(被唤醒进程从阻塞态→就绪态)
3.实现进程互斥
分析问题,确定临界区
设置互斥信号量mutex,初值为1
互斥问题,信号量初值为1
临界区之前时信号量执行P操作,申请资源
临界区之后对信号量执行V操作,释放资源
代码描述

4.实现进程同步
分析问题,找出哪里需要实现"一前一后"的同步关系
设置同步信号量S,初始值为0
同步问题,信号量初值为0
"前操作"之后执行V操作
前V后P
"后操作"之前执行P操作
代码描述

5.实现进程的前驱关系
分析问题,画出前驱图,把每一对前驱关系都看成一个同步问题
前驱关系问题, 本质上就是多级 同步问题
为每一对前驱关系设置同步信号量,初值为0
在每个"前操作"之后执行V操作
在每个"后操作"之前执行P操作
除了互斥、同步问题外,还会考察有多个资源的问题, 有多少资源就把信号量初值设为多少。申请资源时进行P操作, 释放资源时进行V操作即可
2.3.4 管程
为什么要引入管程
解决信号量机制编程麻烦、易出错的问题
组成
共享数据结构
对数据结构初始化的语句
一组用来访问数据结构的过程(函数)
基本特征
各外部进程/线程只能通过管程提供的特定"入口"才能访问共享数据
每次仅允许一个进程在管程内执行某个内部过程
拓展
拓展1:用管程解决生产者消费者问题
代码描述
引入管程的目的无非就是要更方便地实现进程互斥和同步
1.需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
2.需要在管程中定义用于访问这些共享数据的“入ロ”ーー其实就是一些函数(如生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
3.只有通过这些特定的“入口”才能访问共享数据
4.管程中有很多“入口”,但是每次只能开放其中一个“入ロ”,并且只能让一个进程或线程进入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证个时间段内最多只会有一个进程在访问缓冲区。注意:这种互斥特性是由编译器负责实现的,程序员不用关心)
5.可在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”);可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。
程序员可以用某种特殊的语法定义一个管程(比如: monitor Producerconsumer. end monitor;),之后其他程序员就可以使用这个管程提供的特定“入口”很方便地使用实现进程同步/互斥了
拓展2:Java中类似管程的机制
补充
各进程必须互斥访问管程的特性是由编译器实现的
可在管程中设置条件变量及等待/唤醒操作以解決同步问题
2.3.5 经典同步问题
1.生产者-消费者问题
同步问题
1.单生产者-单消费者
1.问题描述
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。(注:这里的“产品”理解为某种数据)
生产者、消费者共享一个初始为空、大小为n的缓冲区
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待
缓冲区是临界资源,各进程必须互斥地访问
2.问题分析
1.关系分析
互斥关系:生产者和消费者对缓存区的访问
同步关系:生产者生产之后,消费者才能消费
2.整理思路
根据各进程的操作流程确定P、V操作的大致顺序
3.信号量设置
信号量mutex设为1
互斥信号量,用于控制互斥访问缓冲池
信号量full设为0
用于记录当前缓存池中“满”缓存区数
信号量empty设为n
用于记录当前缓存区中的“空”缓存区数
3.如何实现

思考
能否改变相邻P、V操作的顺序?
不能,如果改变,则会导致死锁
2.多生产者-多消费者
1.问题描述
桌子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。用PV操作实现上述过程。

两个生产者,两个消费者,一个共享缓存区
2.问题分析
1.关系分析
互斥关系:对缓存区(盘子)的访问要互斥地进行
同步关系(一前一后): 1.父亲将苹果放入盘子后,女儿才能取苹果 2.母亲将橘子放入盘子后,儿子才能取橘子 3.只有盘子为空时,父亲或母亲才能放入水果
2.整理思路
互斥:在临界区前后分别PV
同步:前V后P

3.信号量设置
信号量mutex设为1
实现互斥访问盘子(缓存区)
也可以不设置(plate为1)
信号量apple设为0
盘中有几个苹果
信号量orange设为0
盘中有几个橘子
信号量plate设为1
盘子中还可以放多少个水果
3.如何实现


2.读者-写者问题
互斥问题
1.问题描述
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。
因此要求
①允许多个读者可以同时对文件执行读操作
②只允许一个写者往文件中写信息
③任一写者在完成写操作之前不允许其他读者或写者工作
④写者执行写操作前,应让已有的读者和写者全部退出。
2.问题分析
1.关系分析
两类进程
写进程
读进程
互斥关系
写进程——写进程
写进程——读进程
读进程与读进程不存在互斥问题
2.整理思路
根据各进程的操作流程确定P、V操作的大致顺序
3.信号量设置
信号量rw设为1
用于实现对共享文件的互斥访问
信号量mutex设为1
用于保证对count变量的互斥访问
信号量w设为1
用于实现“写优先”
3.如何实现
1.没有实现“写优先”(读写公平)
2.实现“写优先”(读写公平)
写者不会饥饿,但也不是真正的“写优先”,而是相对公平的先来先服务原则
分析以下并发执行P(w)的情况
读者1→读者2
写者1→写者2
写者1→读者1
读者1→写者1→读者2
写者1→读者1→写者2
3.哲学家进餐问题
1.问题描述
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,オ试图拿起左、右两根筷子(一根一根地拿起)。如果筷子己在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
2.问题分析
1.关系分析
5个哲学家进程
5位哲学家与左右邻居对其中间筷子的访问是互斥关系
2.思路整理
这个问题中只有互斥关系
每个哲学家进程需要同时持有两个临界资源才能开始吃饭
如何避免临界资源分配不当造成的死锁现象,是哲学家问题的精髓
3.信号量设置
互斥信号量chopstick[5]={1,1,1,1,1}
用于实现对5个筷子的互斥访问
对哲学家按0~4编号
哲学家i左边的筷子编号为i,右边的筷子编号为(i+1)%5
3.如何实现
①可以对哲学家进程施加一些限制条件,比如最多允许四个哲学家同时进餐。这样可以保证至少有一个哲学家是可以拿到左右两只筷子的
②要求奇数号哲学家先拿左边的筷子,然后再拿右边的筷子,而偶数号哲学家刚好相反。用这种方法可以保证如果相邻的两个奇偶号哲学家都想吃饭,那么只会有其中一个可以拿起第一只筷子,另一个会直接阻塞。这就避免了占有一支后再等待另一只的情况。
③仅当一个哲学家左右两支筷子都可用时才允许他抓起筷子
更准确的说法应该是:各哲学家拿筷子这件事必须互斥的执行。这就保证了即使一个哲学家在拿筷子拿到一半时被阻塞,也不会有别的哲学家会继续尝试拿筷子。这样的话,当前正在吃饭的哲学家放下筷子后,被阻塞的哲学家就可以获得等待的筷子了
4.吸烟者问题
1.问题描述
假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供应者就会放另外两种材料再桌上,这个过程一直重复(让三个抽烟者轮流地抽烟)

2.问题分析
1.关系分析
同步关系(从事件的角度来分析)
桌上有组合一 → 第一个抽烟者取走东西
桌上有组合二 → 第二个抽烟者取走东西
桌上有组合三 → 第三个抽烟者取走东西
发出完成信号 → 供应者将下一个组合放到桌上
组合一:纸+胶水 组合二:烟草+胶水 组合三:烟草+纸
2.整理思路
前V后P

3.设置信号量
信号量offer1设为0
桌上组合一的数量
信号量offer2设为0
桌上组合二的数量
信号量offer3设为0
桌上组合三的数量
信号量finish设为0
抽烟是否完成
3.如何实现
2.4 死锁
2.4.1 死锁的概念
什么是死锁
各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进
死锁、饥饿、死循环的区别
都是进程无法顺利向前推进的现象(故意设计的死循环除外)
死锁:至少是两个进程一起死锁,死锁进程处于阻塞态
饥饿:可以只有一个进程饥饿,饥饿进程可能阻塞也可能就绪
死循环:可能只有一个进程发生死循环,死循环的进程可上处理机
死锁和饥饿是操作系统要解决的问题,死循环是应用程序员要解決的
死锁产生的必要条件
只要其中任一条件成立,死锁就不会发生
互斥条件
对必须互斥使用的资源的争抢才会导致死锁
不可剥夺条件
进程保持的资源只能主动释放,不可强行剥夺
请求和保持条件
保持着某些资源不放的同时,请求别的资源
循环等待条件
存在一种进程资源的循环等待链
循环等待未必死锁,死锁一定有循环等待
如果同类资源数大于1,则即使有循环等待,也未必发生死锁。但如果系统中每类资源都只有一个,那循环等待就是死锁的充分必要条件了
什么时候会发生死锁
对不可剥夺资源的不合理分配,可能导致死锁
1.对系统资源的竞争
各进程对不可剥夺的资源(如打印机)的竞争可能引起死锁,对可剥夺的资源(CPU)的竞争是不会引起死锁的
2.进程推进顺序非法
请求和释放资源的顺序不当,也同样会导致死锁。例如,并发执行的进程P1、P2分别申请并占有了资源R1、R2,之后进程P1又紧接着申请资源R2,而进程P2又申请资源R1,两者会因为申请的资源被对方占有而阻塞,从而发生死锁
3.信号量的使用不当也会造成死锁
如生产者-消费者问题中,如果实现互斥的P操作在实现同步的P操作之前,就有可能导致死锁。(可以把互斥信号量、同步信号量也看做是一种抽象的系统资源)
2.4.2 死锁的处理策略
1.预防死锁
破坏死锁产生的四个必要条件中的一个或几个
2.避免死锁
避免系统进入不安全状态(银行家算法)
3.死锁的检测及解除
允许死锁发生,系统负责检测出死锁并解除
2.4.3 死锁预防
破坏互斥条件
将临界资源改造为可共享使用的资源(如 SPOOLing技术)
缺点
可行性不高,很多时候无法破坏互斥条件
破坏不剥夺条件
方案一,申请的资源得不到满足时,立即释放拥有的所有资源
方案二,申请的资源被其他进程占用时,由操作系统协助剥夺(考虑优先级)
缺点
实现复杂;剥夺资源可能导致部分工作失效;
反复申请和释放导致系统开销大;可能导致饥饿
破坏请求和保持条件
静态分配方法:运行前分配好所有需要的资源,之后一直保持
缺点
资源利用率低;可能导致饥饿
破坏循环等待条件
顺序资源分配法:给资源编号,必须按编号从小到大的顺序申请资源
缺点
不方便增加新设备;会导致资源浪费;用户编程麻烦
2.4.4 死锁避免
什么是安全序列
所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要能找出一个安全序列,系统就是安全状态。当然,安全序列可能有多个
什么是系统的不安全状态,与死锁有何联系
如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了不安全状态。这就意味着之后可能所有进程都无法顺利的执行下去。当然,如果有进程提前归还了一些资源,那系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑到最坏的情况。
如果系统处于安全状态,就一定不会发生死锁。如果系统进入不安全状态,就可能发生死锁(处于不安全状态未必就是发生了死锁,但发生死锁时一定是在不安全状态)
如何避免系统进入不安全状态——银行家算法
核心思想
在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待
数据结构
Available
长度为m的一维数组 Available 表示还有多少可用资源
Max
n*m矩阵 Max 表示各进程对资源的最大需求数
Allocation
n*m矩阵 Allocation 表示已经给各进程分配了多少资源
Need
Max – Allocation = Need矩阵表示各进程最多还需要多少资源
Request
用长度为m的一位数组 Request 表示进程此次申请的各种资源数
银行家算法步骤
①检查此次申请是否超过了之前声明的最大需求数
②检查此时系统剩余的可用资源是否还能满足这次请求
③试探着分配,更改各数据结构
④用安全性算法检查此次分配是否会导致系统进入不安全状态
安全性算法步骤
①检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。
②不断重复上述过程,看最终是否能让所有进程都加入安全序列
2.4.5 死锁检测和解除
如何检测
数据结构:资源分配图
两种结点
进程结点
对应一个进程
资源结点
对应一类资源,一类资源可能有多个
两种边
进程结点——>资源结点(请求边)
资源节点——>进程结点(分配边)
死锁检测算法
依次消除与不阻塞进程相连的边,直到无边可消
注:所谓不阻塞进程是指其申请的资源数还足够的进程
死锁定理:若资源分配图是不可完全简化的,说明发生了死锁
题中一般会给出资源分配图。 不过也要小心与数据结构结合考察
如何解除
①资源剥夺法
挂起(暂时放到外存上)某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但是应防止被挂起的进程长时间得不到资源而饥饿
②撤销进程法(终止进程法)
强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。这种方式的优点是实现简单,但所付出的代价可能会很大。因为有些进程可能已经运行了很长时间,已经接近结束了,一旦被终止可谓功亏一篑,以后还得从头再来。
③进程回退法
让一个或多个死锁进程回退到足以避免死锁的地步。这就要求系统要记录进程的历史信息,设置还原点。
如何决定“对谁动手”
1.进程优先级
优先级低的
2.已执行多长时间
执行时间少的
3.还要多久能完成
优先让马上可以执行结束的进程获得资源
4.进程已经使用了多少资源
占用资源多的
5.进程是交互式的还是批处理式的
批处理