操作系统-进程、线程、死锁、管程
2.1 进程
定义:由程序段、
-
PCB是进程存在的唯一标志,所谓创建、撤销进程即是创建、撤销进程实体中的PCB
-
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位
PCB的组成
进程的组织
链接方式:按照进程状态将PCB分为多个队列,操作系统持有指向各个队列的指针;包括执行指针、就绪队列指针、阻塞队列指针
索引方式:根据进程状态的不同,建立几张索引表,操作系统持有指向各个索引表的指针;执行指针、就绪表指针、阻塞表指针
进程的特征
-
动态性:是进程最基本的特征
-
并发性;内存中有多个进程实体,各进程可并发执行
-
独立性:进程是能独立运行、独立获得资源、独立接受调度的基本单位
-
异步性:各进程按各自独立的、不可预知的速度向前推进,操作系统要提供“进程同步机制”来解决异步问题
-
结构性
进程的状态和转换
五种基本状态
创建态、运行态、就绪态(拥有除了处理机所有的资源)、阻塞态、终止态(进程撤销,回收进程拥有的资源)
进程的控制
用原语实现进程控制(关中断和开中断指令实现),原语的特点是执行期间不允许中断
-
进程的创建
引起进程创建的事件:用户登录、作业调度、提供服务、应用请求
创建原语:申请空白PCB -> 为新进程分配所需资源 -> 初始化PCB -> 将PCB插入就绪队列
-
进程的终止
引起进程终止的事件:正常结束、异常结束、外界干预
撤销原语:从PCB集合中找到终止进程的PCB -> 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程 -> 终止其所有子进程 -> 将该进程拥有的所有资源归还给父进程或操作系统 -> 删除PCB
-
进程的阻塞
引起进程阻塞的事件:需要等待系统分配某种资源、需要等待相互合作的其他进程完成工作
阻塞原语:找到要阻塞的进程对应的PCB -> 保护进程运行现场,将PCB状态信息设置为“阻塞态” -> 将PCB插入相应事件的等待队列
-
进程的唤醒
引起进程唤醒的事件:等待事件发生
唤醒原语:在事件等待队列中找到PCB -> 将PCB从等待队列移除,设置进程为就绪态 -> 将PCB插入就绪队列,等待被调度
-
进程的切换
引起进程切换的事件:当前进程时间片刻、有更高优先级的进程到达、当前进程主动阻塞、当前进程终止
切换原语:将运行环境信息存入PCB -> PCB移入相应队列 -> 选择另一个进程执行,并更新其PCB -> 根据PCB恢复新进程所需的运行环境
进程通信
共享存储
每个进程的地址空间是各自独立的,因而操作系统提供共享空间,供进程之间互斥访问(不能同时访问);分为基于数据结构的共享(低级通信方式)和基于存储区的共享(高级通信方式)
管道存储
管道是用于读写进程的一个共享文件,实际就是在内存中开辟一个大小固定的缓冲区
-
管道只能半双工通信
-
各进程互斥访问信道
-
管道写满时,写进程的系统调用将被阻塞,等待进程把信息取走;进程数据全部取走后,管道变空,读进程将被阻塞;且如果没写满就不允许读,如果没读空,就不允许写
-
数据一旦被读出,就从管道中被抛弃,这就意味着读进程最多只能有一个
消息传递
以格式化的消息为单位,通过操作系统提供的“发送消息”和“接收消息”两个原语进行数据交换;分为直接通信方式和间接通信方式(将格式化的消息存储在“邮箱中”)
线程
进程的进一步细分
线程的实现方式
-
用户级线程:对用户不透明,对操作系统透明;线程的管理工作(包括切换)都由应用程序负责
(多对一模型)缺点:并发度不高
-
内核级线程:线程的管理工作由操作系统内核完成,切换必须在核心态下完成
(一对一模型)缺点:一个用户进程占用太多内核级线程,开销太大
在同时支持用户级和内核级线程的系统中,可采用二者组合的方式,将N个用户级线程映射到M个内核级线程上(N>=M),但是只有内核级线程才是处理机分配的单位
2. 2 调度
定义:当有一堆任务要处理,但由于资源有限,这些事情无法同时处理,需要确定某种规则来决定处理这些任务的顺序
调度的三层次
高级调度(作业调度):内存空间有限,有时无法将用户提交的作业全部放入内存,因此需要确定某种规则来决定将作业调入内存的顺序,并建立相应的进程(PCB),作业调出时,撤销PCB
创建态 -> 就绪态
$$
中级调度:可将暂时不能运行的进程调至外存等待,等它重新具备了运行条件且内存又有空闲时,再重新调入内存
-
优点可以提高内存利用率和系统吞吐量
-
中级调度发生的频率要比高级调度更高
-
暂时调到外存等待的进程状态为挂起状态;PCB仍保留在内存的挂起队列中
\left\{\begin{matrix} 挂起态 & -> & 就绪态\\ 阻塞挂起& -> & 阻塞态 \end{matrix}\right.
$$
挂起状态又可以进一步分为就绪挂起、阻塞挂起状态
低级调度(进程调度):选取进程,分配处理机,发生频率最高
就绪态 -> 运行态
$$
处理机进程调度的时机
进程需要进行进程调度与切换的时机:分为主动放弃和被动放弃
进程不能进行进程调度与切换的时机
-
进程在操作系统内核程序临界区中不能进行调度和切换;在普通临界区可以进行处理机调度(各进程互斥访问临界资源的区域)
-
进程在处理中断的过程中、在原子操作过程中,不能进行进程调度与切换的情况
处理机进程调度的方式
非剥夺调度方式(非抢占方式):只允许进程主动放弃处理机
剥夺调度方式(抢占方式):可以主动放弃也可以被动放弃
评价调度算法的指标
利用率 =忙碌的时间/总时间
$$
系统吞吐量:单位时间内完成作业的数量
系统吞吐量 = 作业总量/完成时间
$$
周转时间 = 作业完成时间-作业提交时间
$$
带权周转时间 = (作业完成时间-作业提交时间)/作业实际运行的时间
$$
等待时间:进程/作业处于等待处理机状态时间之和
-
进程和作业的等待时间要区分
响应时间:指从用户提出请求到首次响应的时间
调度算法
饥饿:作业无法得到响应
-
先来先服务算法(FCFS,First Come First Serve):非抢占式算法,对于长作业有利,对于短作业无利
-
短作业优先算法(SJF,Shortest Job First):非抢占式,会有进程饥饿问题
抢占式的短作业优先算法——最短剩余时间算法(SRTN):当有进程加入就绪队列和一个进程完成时都会计算运行剩余时间,调度剩余时间最小的进程
-
高响应比优先算法(HRRN,Highest Response Ratio Next):非抢占式,综合了两个进程的等待和运行时间,不会导致饥饿
响应比 = (等待时间+要求服务时间)/要求服务时间
$$
-
时间片轮转算法(RR,Round-Robin):按照各进程到达就绪队列的顺序,轮流让各个进程执行一个时间片;若进程再一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队;若时间片没结束进程就执行结束,则也会调用其他进程;不会导致饥饿
通常时间片长度的选择使得进程的开销占比不超过1%即可
-
优先级调度算法:
-
非抢占式:每次调用已经到达且优先级最高的进程/作业
-
抢占式:选择当前已到达且优先级最高的进程,会发生抢占(一个进程没执行结束就被抢占)
-
优先级分为静态优先级和动态优先级,通常,系统进程优先级高于用户进程,前台进程优先级高于后台进程,I/O型进程优先级(或称I/O繁忙型进程)高于计算型进程(或称CPU繁忙型进程)
-
多级反馈队列调度算法
-
设置多级就绪队列,优先级从高到低,时间片从小到大
-
新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若时间片用完进程还未结束,则进程进入下一级队列队尾;如果此时已经是在最下级的队列,则重新放回该队列队尾
-
只有第K级队列为空时,才会为k+1级队头的进程分配时间片;若有更高优先级的进入队列,则会被抢占处理机,被抢占处理机的进程重新放回原队列队尾
2.3 进程同步
进程同步概念
并发性带来了异步性,有时需要通过进程同步解决这种异步问题,即是进程异步的制约关系
2.4 进程互斥
四个部分
-
进入区:检查是否可以进入临界区,若可进入,则“上锁”
-
临界区:访问临界资源的那段代码
-
退出区:负责“解锁”
-
剩余区:其余代码部分
需要遵循的原则
-
闲则让进
-
忙则等待
-
有限等待:要在有限时间内进入临界区,保证不会饥饿
-
让权等待:进不了临界区的进程,要释放处理机,防止忙等
进程互斥的软件实现方法
1、单标志法:两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程
违背了“空闲让进”原则
2、双标志先检查法:设置一个布尔型数组,数组中各个元素用来标记各进程像进入临界区的意愿
违背了“忙则等待”原则
3、双标志后检查法:
违背了“空闲让进”“有限等待”原则,产生“饥饿”现象;
各缺陷的根源:并发情况
4、Peterson算法:在双标志后检查法的基础上,如果双方都争着进入临界区,则可以让进程尝试主动让对方先使用临界区(主动争取->主动谦让->检查对方是否也想使用)
进程互斥的硬件实现方法
1、中断屏蔽方法:利用开/关中断指令实现,不适用于多处理机;只能用于操作系统内核进程,不适用于用户进程(因为开/关中断只能运行在内核态,这组指令如果能让用户随意使用会很危险)
2、TS(或TSL,TestAndSetLock)指令:硬件实现,不允许中断
缺点:不满足“让权等待”
3、SWAP指令(或XCHG指令):硬件实现,不允许中断
与TS指令实现的功能相似
缺点:不满足“让权等待”
2.5 信号量机制
定义:用户进程可以通过使用操作系统提供的一对原语(wait(S) 和 signal(S),又称P、V操作)来对信号量进行操作,从而很方便的实现了进程互斥、进程同步
信号量
一个变量,用来表示系统中某种资源的数量
整型信号量:用一个整数型的变量作为信号量,用来表示系统中某种资源的数量(只能进行初始化、P操作、V操作三种操作)
记录型信号量
优点:可以实现进程互斥、进程同步
信号量机制实现进程互斥、同步、前驱
生产者消费者问题
多生产者、多消费者问题
当互斥资源只有1时,互斥信号量可以去掉;大于1时不可去掉
互斥的原语一定要放在同步之后,否则会出现死锁
吸烟者问题
读者-写者问题
解决一气呵成时候应该用互斥信号量
哲学家进餐问题
信号量设置:chopsticks[5]={1,1,1,1,1}用于实现对5个筷子的互斥访问,并对哲学家按0~4编号,哲学家i左边的筷子编号为i,右边的筷子编号为(i+1)%5
2.6 死锁
定义:各进程因竞争资源而造成的一种互相等待对方资源的,导致各进程都阻塞,无法向前推进的现象
死循环:某进程执行过程中一直跳不出某个循环的现象
产生死锁的四个条件
-
互斥条件
-
不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走
-
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求
-
循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求
发生死锁时一定有循环等待,但是发生循环等待时未必死锁
发生死锁的时机
-
对系统资源的竞争
-
进程推进顺序不当
-
信号量的使用不当也会造成死锁(比如互斥信号量在同步信号量之前时)
死锁的处理策略
1、预防死锁
-
破环互斥条件(SPOOLing 技术,少用)
-
破环不剥夺条件:当进程请求新的资源得不到满足时,主动释放和被动释放
缺点:实现复杂;造成前一阶段工作的失效;增加系统资源开销,降低系统吞吐量;若一直重复释放之前获得的资源,释放之后又获取不到,就会导致进程饥饿
-
破环请求和保持条件:可以采用静态分配方法,运行前一次申请完它所需要的全部资源
缺点:运行期间保持某些资源,资源利用率低,该策略也有可能导致某些进程饥饿
-
破环循环等待条件:可采用顺序资源分配法,首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源(即编号相同的资源)一次申请完
缺点:不方便增加新的设备,可能需要重新分配所有的编号;进程实际使用资源的顺序可能和编号递增顺序不一致,会导致资源的浪费;必须按规定次序申请资源,用户编程麻烦
2、避免死锁
安全序列:指如果系统按照这种序列分配资源,则每个进程都能顺利完成;安全序列可能有多个
安全与不安全状态:只要能找到安全序列,系统就是安全状态,否则就是不安全状态;系统处于安全状态一定不会发生死锁,进入不安全状态,可能发生死锁
银行家算法
3、检测和解除
死锁的检测
-
用某种数据结构来保存资源的请求和分配信息;
-
提供一种算法,利用上述信息来检测系统是否已经进入死锁状态
如果进程执行后最终能够消除所有边,就称这个图是可完全简化的,此时一定没有发生死锁;否则就是发生了死锁
检测死锁的算法:1)在资源分配图中找出既不阻塞又不是孤点的进程Pi,消去它所有的请求边和分配边(相当于进程执行结束),使之成为孤点
2)根据1)中的方法进行一系列简化后,若能消去途中所有的边,则称该图是可完全简化的(死锁定理:若某时刻系统的资源分配图是不可完全简化的,那么此时系统死锁);否则化简资源分配图后,还连着边的那些进程就是死锁进程
死锁的解除
-
资源剥夺法:挂起某些死锁进程,并抢占它的资源
-
撤销进程法
-
进程回退法:让一个或多个死锁进程回退到足以避免死锁的地步,要求胸痛记录进程的历史信息,设置还原点(较麻烦)
如何决定解除哪个进程?
进程优先级、已执行时间、执行结束还需要的时间、进程已用资源、进程交互式还是批处理式
2.7 管程
定义:管程是一种特殊的软件模块(类似于类),由这些部分组成
-
局部于管程的共享数据结构说明
-
对该数据结构进行操作的一组过程
-
对局部于管程的共享数据设置初始值的语句
-
名字
管程的基本特征
-
局部于管程的数据只能被局部于管程的过程所访问;一个过程只有通过调用管程内的过程才能进入管程内访问共享数据
-
每次仅允许一个进程在管程内执行某个内部过程
-
需要在管程中定义共享数据、访问共享数据的“入口”
-
管程中有很多“入口”,但每次只能开放其中一个“入口”,并且只能让一个进程或线程进入,这种互斥特性是由编译器负责实现的,程序员不需要关心
-
可在管程中设置条件变量及等待/唤醒操作以解决同步问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)