2.4 死锁
在学习本节时,请读者思考以下问题:
1)为什么会产生死锁?产生死锁有什么条件?
2)有什么办法可以解决死锁问题?
学完本节,读者应了解死锁的由来、产生条件及基本解决方法,区分避免死锁和预防死锁。
2.4.1 死锁的概念
1. 死锁的定义
在多道程序系统中,由于进程的并发执行,极大提升了系统效率。然而,多个进程的并发执行也带来了新的问题 ------ 死锁。所谓死锁,是指多个进程因竞争资源而造成的一种僵局(互相等待对方手里的资源),使得各个进程都被阻塞,若无外力干涉,这些进程都无法向前推进。
下面通过一些实例来说明死锁现象。
先看生活中的一个实例。在一条河上有一座桥,桥面很窄,只能容纳一辆汽车通行。若有两辆汽车分别从桥的左右两端驶上该桥,则会出现下述冲突情况:此时,左边的汽车占有桥面左边的一段,右边的汽车占有桥面右边的一段,要想过桥则需等待左边或右边的汽车向后行驶以退出桥面。但若左右两边的汽车都只想向前行驶,则两辆汽车都无法过桥。
在计算机系统中也存在类似的情况。例如,某计算机系统中只有一台打印机和一台输入设备,进程 P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程 P2 所占用,而 P2 在未释放打印机之前,又提出请求使用正被 P1 占用的输入设备。这样,两个进程相互无休止地等待下去,均无法继续向前推进,此时两个进程陷入死锁状态。
2. 死锁与饥饿
一组进程处于死锁状态是指组内的每个进程都在等待一个事件,而该事件只可能由组内的另一个进程产生。与死锁相关的另一个问题是饥饿,即进程在信号量内无穷等待的情况。
产生饥饿的主要原因是:当系统中有多个进程同时申请某类资源时,由分配策略确定资源分配给进程的次序,有的分配策略可能是不公平的,即不能保证等待时间上界的存在。在这种情况下,即使系统未发生死锁,某些进程也可能长时间等待。当等待时间给进程的推进带来明显影响时,称发生了饥饿。例如,当有多个进程需要打印文件时,若系统分配打印机的策略是最短文件优先,则长文件的打印任务将因短文件的源源不断到来而被无限期推迟,最终导致饥饿,甚至"饿死"。饥饿并不表示系统一定会死锁,但至少有一个进程的执行被无限期推迟。
死锁和饥饿的共同点都是进程无法顺利向前推进的现象。
死锁和饥饿的主要差别:
①发生饥饿的进程可以只有一个;而死锁是因循环等待对方手里的资源而导致的,因此,若有死锁现象,则发生死锁的进程必然大于或等于两个。
②发生饥饿的进程可能处于就绪态(长期得不到CPU,如SJF算法的问题),也可能处于阻塞态(如长期得不到所需的I/O设备,如上述举例);而发生死锁的进程必定处于阻塞态。
3. 死锁产生的原因
**命题追踪** 单类资源竞争时发生死锁的临界条件的分析(2009、2014)
(1)系统资源的竞争
通常系统中拥有的不可剥夺资源(如磁带机、打印机等),其数量不足以满足多个进程运行的需要,使得进程在运行过程中,会因争夺资源而陷入僵局。只有对不可剥夺资源的竞争才可能产生死锁,对可剥夺资源(如CPU和主存)的竞争是不会引起死锁的。
(2)进程推进顺序非法
请求和释放资源的顺序不当,也同样会导致死锁。例如,进程 P1,P2 分别保持了资源 R1,R2,而 P1申请资源 R2、P2 申请资源 R1时,两者都会因为所需资源被占用而阻塞,于是导致死锁。
信号量使用不当也会造成死锁。进程间彼此相互等待对方发来的消息,也会使得这些进程无法继续向前推进。例如,进程A等待进程B发的消息,进程B又在等待进程A发的消息,可以看出进程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。
4. 死锁产生的必要条件
产生死锁必须同时满足以下4个条件,只要其中任一条件不成立,死锁就不会发生。
1)互斥条件。进程要求对所分配的资源(如打印机)进行排他性使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
2)不可剥夺条件。进程所获得的资源在未使用完之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
3)请求并保持条件。进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

资源分配图含圈而系统又不一定有死锁的原因是,同类资源数大于1。但若系统中每类资源都只有一个资源,则资源分配图含圈就变成了系统出现死锁的充分必要条件。
要注意区分不可剥夺条件与请求并保持条件。下面用一个简单的例子进行说明:若你手上拿着一个苹果(即便你不打算吃),别人不能将你手上的苹果拿走,则这就是不可剥夺条件;若你左手拿着一个苹果,允许你右手再去拿一个苹果,则这就是请求并保持条件。
- 下列情况中,可能导致死锁的是( )。
A. 进程释放资源
B. 一个进程进入死循环
C. 多个进程竞争资源出现了循环等待
D. 多个进程竞争使用共享型设备
01.C
引起死锁的 4 个必要条件是:互斥、占有并等待、非剥夺和循环等待。本题中,出现了循环等待的现象,意味着可能导致死锁。进程释放资源不会导致死锁,进程自己进入死循环只能产生 "饥饿",不涉及其他进程。共享型设备允许多个进程申请使用,因此不会造成死锁。再次提醒,死锁一定要有两个或两个以上的进程才会导致,而饥饿可能由一个进程导致。
5. 死锁的处理策略
为使系统不发生死锁,必须设法破坏产生死锁的4个必要条件之一,或允许死锁产生,但当死锁发生时能检测出死锁,并有能力实现恢复。
1)死锁预防。设置某些限制条件,破坏产生死锁的4个必要条件中的一个或几个。
2)避免死锁。在资源的动态分配过程中,用某种方法防止系统进入不安全状态。
3)死锁的检测及解除。无须采取任何限制性措施,允许进程在运行过程中发生死锁。通过系统的检测机构及时地检测出死锁的发生,然后采取某种措施解除死锁。
预防死锁和避免死锁都属于事先预防策略,预防死锁的限制条件比较严格,实现起来较为简单,但往往导致系统的效率低,资源利用率低;避免死锁的限制条件相对宽松,资源分配后需要通过算法来判断是否进入不安全状态,实现起来较为复杂。
死锁的几种处理策略的比较见表2.5。

2.4.2 死锁预防
**命题追踪** 死锁预防的特点(2019)
预防死锁的发生只需破坏死锁产生的4个必要条件之一即可。
1. 破坏互斥条件
若将只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。但有些资源根本不能同时访问,如打印机等临界资源只能互斥使用。所以,破坏互斥条件而预防死锁的方法不太可行,而且为了系统安全,很多时候还必须保护这种互斥性。
2. 破坏不可剥夺条件
当一个已经保持了某些不可剥夺资源的进程,请求新的资源而得不到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请。这意味着,进程已占有的资源会被暂时释放,或者说是被剥夺了,从而破坏了不可剥夺条件。
该策略实现起来比较复杂。释放已获得的资源可能造成前一阶段工作的失效,因此这种方法常用于状态易于保存和恢复的资源,如CPU的寄存器及内存资源,一般不能用于打印机之类的资源。反复地申请和释放资源既影响进程推进速度,又增加系统开销,进而降低了系统吞吐量。
3. 破坏请求并保持条件
要求进程在请求资源时不能持有不可剥夺资源,可以通过两种方法实现:
1)采用预先静态分配方法,即进程在运行前一次申请完它所需要的全部资源。在它的资源未满足前,不让它投入运行。在进程的运行期间,不会再提出资源请求,从而破坏了"请求"条件。在等待期间,进程不占有任何资源,从而破坏了"保持"条件。
2)允许进程只获得运行初期所需的资源后,便可开始运行。进程在运行过程中再逐步释放已分配给自己且已使用完毕的全部资源后,才能请求新的资源。
方法一的实现简单,但缺点也显而易见,系统资源被严重浪费,其中有些资源可能仅在运行初期或快结束时才使用,而且会导致"饥饿"现象,由于个别资源长期被其他进程占用,将导致等待该资源的进程迟迟不能开始运行。方法二则改进了这些缺点。
4. 破坏循环等待条件
为了破坏循环等待条件,可以采用顺序资源分配法。首先给系统中的各类资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源(编号相同的资源)一次申请完。也就是说,一个进程只在已经占有小编号的资源时,才有资格申请更大编号的资源。按此规则,已持有大编号资源的进程不可能再逆向申请小编号的资源,因此不会产生循环等待的现象。
这种方法的缺点:编号必须相对稳定,因此不便于增加新类型设备;尽管在编号时已考虑到大多数进程使用这些资源的顺序,但是进程实际使用资源的顺序还是可能和编号的次序不一致,这就会造成资源的浪费;此外,必须按规定次序申请资源,也会给用户编程带来麻烦。
2.4.3 死锁避免
避免死锁同样属于事先预防策略,但并不是事先采取某种限制措施破坏死锁的必要条件,而是在每次分配资源的过程中,都要分析此次分配是否会带来死锁风险,只有在不产生死锁的情况下,系统才会为其分配资源。这种方法所施加的限制条件较弱,可以获得较好的系统性能。
1. 系统安全状态
避免死锁的方法中,允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次
分配的安全性。若此次分配不会导致系统进入不安全状态,则允许分配;否则让进程等待。
所谓安全状态,是指系统能按某种进程推进顺序(P1,P2,...,Pn)为每个进程Pi分配其所需的资源,直至满足每个进程对资源的最大需求,使每个进程都可顺利完成。此时称P1,P2,...,Pn为安全序列(可能有多个)。若系统无法找到一个安全序列,则称系统处于不安全状态。
**命题追踪** 系统安全状态的分析(2018)
假设系统有三个进程P1,P2和P3,共有12台磁带机。P1需要10台,P2和P3分别需要4台和9台。假设在T0时刻,P1,P2和P3已分别获得5台、2台和2台,尚有3台未分配,见表2.6。

在T0时刻是安全的,因为存在一个安全序列P2,P1,P3,只要系统按此进程序列分配资源,那么每个进程都能顺利完成。也就是说,当前可用资源数为3,先将2台分配给P2以满足其最大需求,P2结束并归还资源后,系统有5台可用;接下来给P1分配5台以满足其最大需求,P1结束并归还资源后,剩余10台可用;最后分配7台给P3,这样P3也能顺利完成。
若在T0时刻后,系统分配1台给P3,剩余可用资源数为2,此时系统进入不安全状态,因为此时已无法再找到一个安全序列。当系统进入不安全状态后,便可能导致死锁。例如,将剩下的2台分配给P2,这样,P2完成后只能释放4台,既不能满足P1又不能满足P3,致使它们都无法推进到完成,彼此都在等待对方释放资源,陷入僵局,即导致死锁。
若系统处于安全状态,则一定不会发生死锁;若系统进入不安全状态,则有可能发生死锁(处于不安全状态未必就会发生死锁,但发生死锁时一定是处于不安全状态)。
2. 银行家算法
**命题追踪** 银行家算法的特点(2013、2019)
银行家算法是最著名的死锁避免算法,其思想是:将操作系统视为银行家,操作系统管理的资源视为银行家管理的资金,进程请求资源相当于用户向银行家贷款。进程运行之前先声明对各种资源的最大需求量,其数量不应超过系统的资源总量。当进程在运行中申请资源时,系统必须先确定是否有足够的资源分配给该进程。若有,再进一步试探在将这些资源分配给进程后,是否会使系统处于不安全状态。若不会,则将资源分配给它,否则让进程等待。

2.4.4 死锁检测和解除
**命题追踪** 死锁避免和死锁检测的区分(2015)
前面介绍的死锁预防和避免算法,都是在为进程分配资源时施加限制条件或进行检测,若系统为进程分配资源时不采取任何预防或避免措施,则应该提供死锁检测和解除的手段。
1. 死锁检测
**命题追踪** 死锁避免和死锁检测对比(2015)
死锁避免和死锁检测的对比。死锁避免需要在进程的运行过程中一直保证之后不可能出现死锁,因此需要知道进程从开始到结束的所有资源请求。而死锁检测是检测某个时刻是否发生死锁,不需要知道进程在整个生命周期中的资源请求,只需知道对应时刻的资源请求。
**命题追踪** 多在资源竞争时发生死锁的临界条件分析(2016、2021)
可用资源分配图来检测系统所处的状态是否为死锁状态。如图2.15(a)所示,用圆圈表示一个进程,用框表示一类资源。一种类型的资源可能有多个,因此用框中的一个圆表示一类资源中的一个资源。从进程到资源的有向边称为请求边,表示该进程申请一个单位的该类资源;从资源到进程的有向边称为分配边,表示该类资源已有一个资源分配给了该进程。
在图2.15(a)所示的资源分配图中,进程P1已分得了两个R1资源,并又请求一个R2资源;进程P2分得了一个R1资源和一个R2资源,并又请求一个R1资源。

简化资源分配图可检测系统状态S是否为死锁状态。简化方法如下:
1)在资源分配图中,找出既不阻塞又不孤立的进程Pi(找出一条有向边与它相连,且该有向边对应资源的申请数量小于或等于系统中已有的空闲资源数量,如在图2.15(a)中,R1没有空闲资源,R2有一个空闲资源。若所有连接该进程的边均满足上述条件,则这个进程能继续运行直至完成,然后释放它所占有的所有资源)。消去它所有的请求边和分配边,使之成为孤立的节点。在图2.15(a)中,P1是满足这一条件的进程节点,将P1的所有边消去,便得到图2.15(b)所示的情况。 这里要注意一个问题,判断某种资源是否有空闲,应该用它的资源数量减去它在资源分配图中的出度,例如在图2.15(a)中,R1的资源数为3,而出度也为3,所以R1没有空闲资源,R2的资源数为2,出度为1,所以R2有一个空闲资源。
2)进程Pi所释放的资源,可以唤醒某些因等待这些资源而阻塞的进程,原来的阻塞进程可能变为非阻塞进程。在图2.15(a)中,P_2就满足这样的条件。根据1)中的方法进行一系列简化后,若能消去图中所有的边,则称该图是可完全简化的,如图2.15(c)所示。
S为死锁的条件是当且仅当S状态的资源分配图是不可完全简化的,该条件为死锁定理。
2. 死锁解除
**命题追踪** 解除死锁的方式(2019)
一旦检测出死锁,就应立即采取相应的措施来解除死锁。死锁解除的主要方法有:
1)资源剥夺法。挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源而处于资源匮乏的状态。
**注意** 在资源分配图中,用死锁定理化简后,还有边相连的那些进程就是死锁进程。
2)撤销进程法。强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。撤销的原则可以按进程优先级和撤销进程代价的高低进行。这种方式实现简单,但付出的代价可能很大,因为有些进程可能已经接近结束,一旦被终止,以后还得从头再来。
3)进程回退法。让一个或多个死锁进程回退到足以回避死锁的地步,进程回退时自愿释放资源而非被剥夺。要求系统保持进程的历史信息,设置还原点。
2.4.5 本节小结
本节开头提出的问题的参考答案如下。
1)为什么会产生死锁?产生死锁有什么条件?
由于系统中存在一些不可剥夺资源,当两个或两个以上的进程占有自身的资源并请求对方的资源时,会导致每个进程都无法向前推进,这就是死锁。死锁产生的必要条件有4个,分别是互斥条件、不剥夺条件、请求并保持条件和循环等待条件。
互斥条件是指进程要求分配的资源是排他性的,即最多只能同时供一个进程使用。
不剥夺条件是指进程在使用完资源之前,资源不能被强制夺走。 请求并保持条件是指进程占有自身本来拥有的资源并要求其他资源。
循环等待条件是指存在一种进程资源的循环等待链。
2)有什么办法可以解决死锁问题?
死锁的处理策略可以分为预防死锁、避免死锁及死锁的检测与解除。
死锁预防是指通过设立一些限制条件,破坏死锁的一些必要条件,让死锁无法发生。
死锁避免指在动态分配资源的过程中,用一些算法防止系统进入不安全状态,从而避免死锁。
死锁的检测和解除是指在死锁产生前不采取任何措施,只检测当前系统有没有发生死锁,若有,则采取一些措施解除死锁。
2.4.6 本节习题精选
一、单项选择题
- 下列情况中,可能导致死锁的是( )。
A. 进程释放资源
B. 一个进程进入死循环
C. 多个进程竞争资源出现了循环等待
D. 多个进程竞争使用共享型设备
01.C
引起死锁的 4 个必要条件是:互斥、占有并等待、非剥夺和循环等待。本题中,出现了循环等待的现象,意味着可能导致死锁。进程释放资源不会导致死锁,进程自己进入死循环只能产生 "饥饿",不涉及其他进程。共享型设备允许多个进程申请使用,因此不会造成死锁。再次提醒,死锁一定要有两个或两个以上的进程才会导致,而饥饿可能由一个进程导致。
- 在哲学家进餐问题中,若所有哲学家同时拿起左筷子,则发生死锁,因为他们都需要右筷子才能用餐。为了让尽可能多的哲学家可以同时用餐,并且不发生死锁,可以利用信号量PV操作实现同步互斥,下列说法中正确的是( )。
A. 使用信号量进行控制的方法一定可以避免死锁
B. 同时检查两支筷子是否可用的方法可以预防死锁,但是会导致饥饿问题
C. 限制允许拿起筷子的哲学家数量可以预防死锁,它破坏了"循环等待"条件
D. 对哲学家顺序编号,奇数号哲学家先拿左筷子,然后拿右筷子,而偶数号哲学家刚好相反,可以预防死锁,它破坏了"互斥"条件
02.C
信号量机制能确保临界资源的互斥访问,不能完全避免死锁,选项 A 错误。
同时检查两支筷子是否可用的方法可以预防死锁,但是会导致资源浪费,因为可能有一些空闲的筷子无法使用,但拿到筷子的哲学家用完餐后,释放筷子,其他哲学家就可以正常用餐,因此不会导致饥饿现象,选项 B 错误。
若限制允许拿起筷子的哲学家数量,则不被允许的哲学家左边的哲学家一定可以拿到两边的筷子,从而破坏 "循环等待" 条件,选项 C 正确。
对哲学家顺序编号,奇数号哲学家先拿左筷子,然后拿右筷子,而偶数号哲学家刚好相反,则相邻的哲学家总有一个可以拿起两边的筷子,但这破坏的是 "循环等待" 条件,而不是 "互斥条件" ,选项 D 错误。
- 下列关于进程死锁的描述中,错误的是( )。
A. 若每个进程只能同时申请或拥有一个资源,则不会发生死锁
B. 若多个进程可以无冲突共享访问所有资源,则不会发生死锁
C. 若所有进程的执行严格区分优先级,则不会发生死锁
D. 若进程资源请求之间不存在循环等待,则不会发生死锁
- C
进程的执行优先级并不能破坏死锁的四个必要条件。即使有高优先级和低优先级的进程,若它们都请求或占有了不可抢占的资源,且形成了环路等待,则死锁仍可能发生。选项 A 可以破坏请求并保持条件,选项 B 可以破坏互斥条件,选项 D 可以破坏循环等待条件。
- 一次分配所有资源的方法可以预防死锁的发生,它破坏死锁4个必要条件中的( )。
A. 互斥
B. 占有并请求
C. 非剥夺
D. 循环等待
- B
发生死锁的 4 个必要条件:互斥、占有并请求、非剥夺和循环等待。一次分配所有资源的方法是当进程需要资源时,一次性提出所有的请求,若请求的所有资源均满足则分配,只要有一项不满足,就不分配任何资源,该进程阻塞,直到所有的资源空闲后,满足进程的所有需求时再分配。这种分配方式不会部分地占有资源,因此打破了死锁的 4 个必要条件之一,实现了对死锁的预防。但是,这种分配方式需要凑齐所有资源,因此当一个进程所需的资源较多时,资源的利用率会较低,甚至会造成进程 "饥饿" 。
- 系统产生死锁的可能原因是( )。
A. 独占资源分配不当
B. 系统资源不足
C. 进程运行太快
D. CPU内核太多
- A
系统死锁的可能原因主要是时间上和空间上的。时间上由于进程运行中推进顺序不当,即调度时机不合适,不该切换进程时进行了切换,可能造成死锁;空间上的原因是对独占资源分配不当,互斥资源部分分配又不可剥夺,极易造成死锁。那么,为什么系统资源不足不是造成死锁的原因呢?系统资源不足只会对进程造成 "饥饿" 。例如,某系统只有三台打印机,若进程运行中要申请四台,显然不能满足,该进程会永远等待下去。若该进程在创建时便声明需要四台打印机,则操作系统立即就会拒绝,这实际上是资源分配不当的一种表现。不能以系统资源不足来描述剩余资源不足的情形。
- 死锁的避免是根据( )采取措施实现的。
A. 配置足够的系统资源
B. 使进程的推进顺序合理
C. 破坏死锁的四个必要条件之一
D. 防止系统进入不安全状态
- D
死锁避免是指在资源动态分配过程中用某些算法加以限制,防止系统进入不安全状态从而避免死锁的发生。选项 B 是避免死锁后的结果,而不是措施的原理。
- 死锁预防是保证系统不进入死锁状态的静态策略,其解决办法是破坏产生死锁的四个必要条件之一。下列方法中破坏了"循环等待"条件的是( )。
A. 银行家算法
B. 一次性分配策略
C. 剥夺资源法
D. 资源有序分配策略
- D
资源有序分配策略可以限制循环等待条件的发生。选项 A 判断是否为不安全状态;选项 B 破坏了占有请求条件;选项 C 破坏了非剥夺条件。
- 可以防止系统出现死锁的手段是( )。
A. 用PV操作管理共享资源
B. 使进程互斥地使用共享资源
C. 采用资源静态分配策略
D. 定时运行死锁检测程序
- C
选项A,PV 操作不能破坏死锁条件,反而可能加强互斥和占有并等待条件。选项 B 同理。选项 C 可以破坏请求并保持条件。选项 D 只能在系统出现死锁时检测,却不能防止系统出现死锁。
- 某系统中有三个并发进程都需要四个同类资源,则该系统必然不会发生死锁的最少资源是( )。
A. 9
B. 10
C. 11
D. 12
- B
资源数为 9 时,存在三个进程都占有三个资源,为死锁;资源数为 10 时,必然存在一个进程能拿到 4 个资源,然后可以顺利执行完其他进程。
- 某系统中共有11台磁带机,X个进程共享此磁带机设备,每个进程最多请求使用3台,则系统必然不会死锁的最大X值是( )。
A. 4
B. 5
C. 6
D. 7
- B
考虑一下极端情况:每个进程已经分配了两台磁带机,那么其中任何一个进程只要再分配一台磁带机即可满足它的最大需求,该进程总能运行下去直到结束,然后将磁带机归还给系统再次分配给其他进程使用。因此,系统中只要满足 2X + 1 = 11 这个条件即可认为系统不会死锁,解得 X = 5,也就是说,系统中最多可以并发 5 个这样的进程是不会死锁的。或者,根据死锁公式,资源数大于进程个数乘以 "每个进程需要的最大资源数减 1" 就不会发生死锁,即 m > n (w - 1),其中 m 是磁带机的数量,n 是进程的数量,w 是每个进程最多请求的磁带机数量。代入可得 11 > n (3 - 1),即 n < 5.5,n 是正整数,因此系统必然不会死锁的最大 n 值是 5。
- 若系统中有5个某类资源供若干进程共享,则不会引起死锁的情况是( )。
A. 有6个进程,每个进程需1个资源
B. 有5个进程,每个进程需2个资源
C. 有4个进程,每个进程需3个资源
D. 有3个进程,每个进程需4个资源
- A
A 项的每个进程只申请一个资源,破坏了请求并保持条件,必然不会发生死锁。或者,根据死锁公式,假设系统共有 m 个资源,n 个进程,每个进程需要 k 个资源,若满足 m > n (k - 1),则系统一定不会发生死锁,代入公式可知选项 B、C、D 均可能发生死锁。
- 解除死锁通常不采用的方法是( )。
A. 终止一个死锁进程
B. 终止所有死锁进程
C. 从死锁进程处抢夺资源
D. 从非死锁进程处抢夺资源
- D
解除死锁的方法有,①剥夺资源法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程;②撤销进程法:强制撤销部分甚至全部死锁进程并剥夺这些进程的资源。
- 采用资源剥夺法可以解除死锁,还可以采用( )方法解除死锁。
A. 执行并行操作 B. 撤销进程 C. 拒绝分配新资源 D. 修改信号量
- B
资源剥夺法允许一个进程强行剥夺其他进程所占有的系统资源。而撤销进程强行释放一个进程已占有的系统资源,与资源剥夺法同理,都通过破坏死锁的 "请求和保持" 条件来解除死锁。拒绝分配新资源只能维持死锁的现状,无法解除死锁。
- 在下列死锁的解决方法中,属于死锁预防策略的是( )。
A. 银行家算法 B. 资源有序分配算法 C. 死锁检测算法 D. 资源分配图化简法
- B
其中,银行家算法为死锁避免算法,死锁检测算法和资源分配图化简法为死锁检测,根据排除法可以得出资源有序分配算法为死锁预防策略。
- 三个进程共享四个同类资源,这些资源的分配与释放只能一次一个。已知每个进程最多需要两个该类资源,则该系统( )。
A. 有些进程可能永远得不到该类资源
B. 必然有死锁
C. 进程请求该类资源必然能得到
D. 必然是死锁
- C
不会发生死锁。因为每个进程都分得一个资源时,还有一个资源可以让任意一个进程满足,这样这个进程可以顺利运行完成进而释放它的资源。
- 以下有关资源分配图的描述中,正确的是( )。
A. 有向边包括指向资源类的分配边和资源类指向进程申请边两类
B. 矩形框表示进程,其中圆点表示申请同一类资源的各个进程
C. 圆圈节点表示资源类
D. 资源分配图是一个有向图,用于表示某时刻系统资源与进程之间的状态
- D
进程指向资源的有向边称为申请边,资源指向进程的有向边称为分配边,选项 A 张冠李戴;矩形框表示资源,其中的圆点表示资源的数量,选项 B 错;圆圈节点表示进程,选项 C 错;选项 D 的说法是正确的。
- 死锁的四个必要条件中,无法破坏的是( )。
A. 环路等待资源 B. 互斥使用资源 C. 占有且等待资源 D. 非抢夺式分配
- B
所谓破坏互斥使用资源,是指允许多个进程同时访问资源,但有些资源根本不能同时访问,如打印机只能互斥使用。因此,破坏互斥条件而预防死锁的方法不太可行,而且在有的场合应该保护这种互斥性。其他三个条件都可以实现。
- 死锁与安全状态的关系是( )。
A. 死锁状态有可能是安全状态
B. 安全状态有可能成为死锁状态
C. 不安全状态就是死锁状态
D. 死锁状态一定是不安全状态
- D
如下图所示,并非所有不安全状态都是死锁状态,但当系统进入不安全状态后,便可能进入死锁状态;反之,只要系统处于安全状态,系统便可避免进入死锁状态;死锁状态必定是不安全状态。
|--------|------------|
| 不安全状态 | 死锁状态 |
| 包含死锁状态 | 是不安全状态的一部分 |
- 死锁检测时检查的是( )。
A. 资源有向图 B. 前驱图 C. 搜索树 D. 安全图
- A
死锁检测一般采用两种方法:资源有向图法和资源矩阵法。前驱图只是说明进程之间的同步关系,搜索树用于数据结构的分析,安全图并不存在。注意死锁避免和死锁检测的区别:死锁避免是指避免死锁发生,即死锁没有发生;死锁检测是指死锁已出现,要把它检测出来。
- 某个系统采用下列资源分配策略。若一个进程提出资源请求得不到满足,而此时没有由于等待资源而被阻塞的进程,则自己就被阻塞。而当此时已有等待资源而被阻塞的进程,则检查所有由于等待资源而被阻塞的进程。若它们有申请进程所需要的资源,则将这些资源取出并分配给申请进程。这种分配策略会导致( )。
A. 死锁 B. 颠簸 C. 回退 D. 饥饿
- D
某个进程主动释放资源不会导致死锁,因为破坏了请求并保持条件,选项 A 错。颠簸也就是抖动,这是请求分页系统中页面调度不当而导致的现象,是下一章讨论的问题,这里权且断定选项 B 是错的。回退是指从此时此刻的状态退回到一分钟之前的状态,假如一分钟之前拥有资源 X,它有可能释放了资源 X,那就不称回到一分钟之前的状态,也就不是回退,选项 C 错。因为进程过于 "慷慨" ,不断把自己已得到的资源送给别人,导致自己长期无法完成,所以是饥饿,选项 D 正确。
- 系统的资源分配图在下列情况下,无法判断是否处于死锁状态的有( )。
I. 出现了环路 II. 没有环路
III. 每种资源只有一个,并出现环路 IV. 每个进程节点至少有一条请求边
A. I、II、III、IV
B. I、III、IV
C. I、IV
D. 以上答案都不正确
- C
出现了环路,只是满足了循环等待的必要条件,而满足必要条件不一定会导致死锁,选项 I 对;没有环路,破坏了循环等待条件,一定不会发生死锁,选项 II 错;每种资源只有一个,又出现了环路,这是死锁的充分条件,可以确定是否有死锁,选项 III 错;即使每个进程至少有一条请求边,若资源足够,则不会发生死锁,但若资源不充足,则有发生死锁的可能,选项 IV 对。
综上所述,选择选项 C。
- 下列关于死锁的说法中,正确的有( )。
I. 死锁状态一定是不安全状态
II. 产生死锁的根本原因是系统资源分配不足和进程推进顺序非法
III. 资源的有序分配策略可以破坏死锁的循环等待条件
IV. 采用资源剥夺法可以解除死锁,还可以采用撤销进程方法解除死锁
A. I、III B. II C. IV D. 四个说法都对
- D
选项 I 正确。
选项 II 正确:这是产生死锁的两大原因。
选项 III 正确:在对资源进行有序分配时,进程间不可能出现环形链,即不会出现循环等待。
选项 IV 正确:资源剥夺法允许一个进程强行剥夺其他进程占有的系统资源。而撤销进程强行释放一个进程已占有的系统资源,与资源剥夺法同理,都通过破坏死锁的 "请求和保持" 条件来解除死锁,所以选择选项 D。
- 下面是并发进程的程序代码,正确的是( )。
A. 进程不会死锁,也不会"饥饿"
B. 进程不会死锁,但是会"饥饿"
C. 进程会死锁,但是不会"饥饿"
D. 进程会死锁,也会"饥饿"
- B
遇到这种问题时千万不要慌张,下面我们来慢慢分析,给读者一个清晰的解题过程:
仔细考察程序代码,可以看出这是一个扩展的单行线问题。也就是说,某单行线只允许单方向的车辆通过,在单行线的入口设置信号量 y,在告示牌上显示某一时刻各方向来车的数量 c1 和 c2,用 c2 修改告示牌上的车辆数量必须互斥进行,为此设置信号量 x1 和 x2。若某方向的车辆需要通过时,则首先要将该方向来车数量 c1 或 c2 增加 1,并查看自己是否是第一个进入单行线的车辆,若是,则获取单行线的信号量 y,并进入单行线。通过此路段以后出单行线时,将该方向的车辆数 c1 或 c2 减 1(当然是利用 x1 或 x2 来互斥修改),并查看自己是否是最后一辆车,若是,则释放单行线的互斥量 y,否则保留信号量 y,让后继车辆继续通过。双方的操作如出一辙。考虑出现一个极端情况,即当某方向的车辆首先占据单行线并后来者络绎不绝时,另一个方向的车辆就再没有机会通过该单行线了。而这种现象是由于算法本身的缺陷造成的,不属于因为特殊序列造成的饥饿,所以它是真正的饥饿现象。因为有信号量的控制,所以死锁的可能性没有了(双方同时进入单行线,在中间相遇,造成双方均无法通过的情景)。
①假设 P1 进程稍快,P2 进程稍慢,同时运行;②P1 进程首先进入 if 条件语句,因此获得了 y 的互斥访问权,P2 被阻塞;③在第一个 P1 进程未释放 y 之前,又有另一个 P1 进入,c1 的值变成 2,当第一个 P1 离开时,P2 仍然被阻塞,这种情形不断发生;④在这种情况下会发生什么事?P1 顺利执行,P2 很郁闷,长期被阻塞。
综上所述,不会发生死锁,但会出现饥饿现象。因此选 B。
- 有两个并发进程,对于如下这段程序的运行,正确的说法是( )。
A. 程序能正确运行,结果唯一
B. 程序不能正确运行,可能有两种结果
C. 程序不能正确运行,结果不确定
D. 程序不能正确运行,可能死锁
- C
本题中两个进程不能正确地工作,运行结果的可能性详见下面的说明。
不确定的原因是由于使用了公共变量 x,考查与变量 x 有关的语句共四处,执行的顺序是 1→2→3→4→5→6→7→8 时,结果是 y = 1, z = 1, t = 2, u = 2, x = 0;并发执行过程是 1→2→5→6→3→4→7→8 时,结果是 y = 0, z = 0, t = 2, u = 2, x = 0;执行的顺序是 5→6→7→8 →1→2→3→4 时,结果是 y = 1, z = 1, t = 2, u = 2, x = 1;执行的顺序是 5→6→1→ 2→7→8→3→4 时,结果是 y = 1, z = 1, t = 2, u = 2, x = 1。可见结果有多种可能性。
显然,无论执行顺序如何,x 的结果只能是 0 或 1,因此语句 7 的条件一定成立,即 t = u = 2 的结果是一定的;而 y = z 必定成立,只可能有 0, 1 两种情况,又不可能出现 x = 1, y = z = 0 的情况,所以总共有 3 种结果(答案中的 3 种)。
- 一个进程在获得资源后,只能在使用完资源后由自己释放,这属于死锁必要条件的( )。
A. 互斥条件 B. 请求和释放条件 C. 不剥夺条件 D. 防止系统进入不安全状态
- C
一个进程在获得资源后,只能在使用完资源后由自己释放,即它的资源不能被系统剥夺,答案为选项 C。
- 假设具有5个进程的进程集合P = {P₀, P₁, P₂, P₃, P₄},系统中有三类资源A, B, C,假设在某时刻有如下状态,见下表。
系统是处于安全状态的,则x, y, z的取值可能是( )。
I. 1, 4, 0
II. 0, 6, 2
III. 1, 1, 1
IV. 0, 4, 7
A. I、II、IV B. I、II C. 仅I D. I、III
- C
选项 I:根据 need 矩阵可知,当 Available 为 (1, 4, 0) 时,可满足 P2 的需求;P2 结束后释放资源,Available 为 (2, 7, 5) 可以满足 P0, P1, P3, P4 中任意一个进程的需求,所以系统不会出现死锁,处于安全状态。
选项 II:当 Available 为 (0, 6, 2) 时,可以满足进程 P0, P3 的需求;这两个进程结束后释放资源,Available 为 (0, 6, 7),仅可以满足进程 4 的需求;P4 结束并释放后,Available 为 (0, 6, 8),此时不能满足余下任意一个进程的需求,因此当前处在非安全状态。
选项 III:当 Available 为 (1, 1, 1) 时,可以满足进程 P0, P2 的需求;这两个进程结束后释放资源,Available 为 (2, 4, 9),此时不能满足余下任意一个进程的需求,处于非安全状态。
选项 IV:当 Available 为 (0, 4, 7) 时,可以满足 P0 的需求,进程结束后释放资源,Available 为 (0, 4, 10),此时不能满足余下任意一个进程的需求,处于非安全状态。
综上分析:只有选项 I 处于安全状态。
- 死锁定理是用于处理死锁的( )方法。
A. 预防死锁 B. 避免死锁 C. 检测死锁 D. 解除死锁
- C
死锁定理是用于检测死锁的方法。
- 某系统有m个同类资源供n个进程共享,若每个进程最多申请k个资源(k≥1),采用银行家算法分配资源,为保证系统不发生死锁,则各进程的最大需求量之和应( )。
A. 等于m B. 等于m + n C. 小于m + n D. 大于m + n
- C
按照银行家算法,只要保证系统中进程申请的最大资源数小于或等于 m,就一定存在一个安全序列。考虑最极端的情况,假如有 n - 1 个进程都申请了 1 个资源,剩下一个进程申请了 m 个资源,则各进程的最大需求量之和为 m + n - 1,此时能保证一定不会发生死锁。
29.采用银行家算法可以避免死锁的发生,这是因为该算法( )。
A. 可以抢夺已分配的资源
B. 能及时为各进程分配资源
C. 任何时刻都能保证每个进程能得到所需的资源
D. 任何时刻都能保证至少有一个进程可以得到所需的全部资源
- D
任何时刻都能保证至少有一个进程可以得到所需的全部资源,这意味着银行家算法可以保证系统中至少存在一个安全序列,使每个进程都能按该顺序得到所需的全部资源并正常结束,不会出现死锁的情况。这也是银行家算法避免死锁的核心思想。
30.用银行家算法避免死锁时,检测到( )时才分配资源。
A. 进程首次申请资源时对资源的最大需求量超过系统现存的资源量
B. 进程已占有的资源数与本次申请的资源数之和超过对资源的最大需求量
C. 进程已占有的资源数与本次申请的资源数之和不超过对资源的最大需求量,且现存资源量能满足尚需的最大资源量
D. 进程已占有的资源数与本次申请的资源数之和不超过对资源的最大需求量,且现存资源量能满足本次申请量,但不能满足尚需的最大资源量
- C
银行家算法要求,进程运行之前先声明它对各类资源的最大需求量,并保证它在任何时刻对每类资源的请求量不超过它所声明的最大需求量。当进程已占有的资源数与本次申请的资源数之和不超过对资源的最大需求量,且现存资源量能满足尚需的最大资源量时,才分配资源。
31.下列各种方法中,可用于解除已发生死锁的是( )。
A. 撤销部分或全部死锁进程
B. 剥夺部分或全部死锁进程的资源
C. 降低部分或全部死锁进程的优先级
D. A 和 B 都可以
- D
解除死锁的方法有两种:撤销死锁进程和剥夺死锁进程的资源。降低死锁进程的优先级是无效的方法,因为它不能改变死锁进程对资源的需求和占有,也不能打破循环等待条件。
32.假定某计算机系统有R1和R2两类可使用资源(其中R1有两个单位,R2有一个单位),它们被进程P1和P2所共享,且已知两个进程均按下列顺序使用两类资源:申请R1→申请R2→申请R1→释放R1→释放R2→释放R1,则在系统运行过程中,( )。
A. 不可能产生死锁
B. 有可能产生死锁,因为R1资源不足
C. 有可能产生死锁,因为R2资源不足
D. 只有一种进程执行序列可能导致死锁
- B
当两个进程都执行完第一步后,即进程 P1 和进程 P2 都申请到了一个 R1 类资源时,随着两个进程向前推进,无论哪个进程执行完第二步,系统都将进入死锁状态,进入死锁状态的原因是两个进程都需要两个 R1 类资源才能运行,但系统中此时已经没有可供分配的 R1 类资源。假定进程 P1 成功执行了第二步,则死锁发生时资源分配图如下:
|----|-------|------|
| 进程 | 已分配资源 | 申请资源 |
| P1 | R1、R2 | R1 |
| P2 | R1 | R1 |
33.【2009 统考真题】某计算机系统中有 8 台打印机,由K个进程竞争使用,每个进程最多需要 3 台打印机。该系统可能发生死锁的K的最小值是( )。A. 2 B. 3 C. 4 D. 5
- C
这类题可用到组合数学中鸽巢原理的思想。考虑最极端的情况,因为每个进程最多需要 3 台打印机,若每个进程已经占有了 2 台打印机,则只要还有多的打印机,总能满足一个进程达到 3 台的条件,然后顺利执行,所以将 8 台打印机分给 K 个进程,每个进程有 2 台打印机,这个情况就是极端情况,K 为 4。或者,假设 M 是打印机的数量,K 是进程的数量,R 是每个进程最多需要打印机的数量。根据死锁公式逆推可得,若 M ≤ K (R - 1),则系统可能发生死锁。将本题的数据代入,可得8≤K×(3−1),即K≥4,所以系统可能发生死锁的K的最小值是4。
34.【2011 统考真题】某时刻进程的资源使用情况见下表,此时的安全序列是( )。
A. P1,P2,P3,P4 B. P1,P3,P2,P4
C. P1,P4,P3,P2 D. 不存在
- D
本题应采用排除法,逐个代入分析。剩余资源分配给P1,待P1执行完后,可用资源数为(2,2,1),此时仅能满足P4的需求,排除选项 A、B;接着分配给P4,待P4执行完后,可用资源数为(2,2,2),此时已无法满足任何进程的需求,排除选项 C。
此外,本题还可以使用银行家算法求解(对选择题来说显得过于复杂)。
本题可根据银行家算法的安全性检查来判断是否存在安全序列。
步骤一:计算各进程的尚需资源数
已知各进程的已分配资源和尚需分配资源,根据公式 "尚需资源数 = 最大需求资源数 - 已分配资源数",结合题目表格信息,可得到各进程的尚需资源数。
步骤二:进行安全性检查
从可用资源(0,2,1)开始,逐一检查各进程的尚需资源数是否能被当前可用资源满足。
对于P1,尚需(0,0,1),可用资源(0,2,1)可以满足,P1完成后释放资源,此时可用资源变为(2,2,1)。
对于P2,尚需(1,3,2),当前可用资源(2,2,1)不能满足。
对于P3,尚需(2,0,0),当前可用资源(2,2,1)可以满足,P3完成后释放资源,此时可用资源变为(2,3,2)。
对于P4,尚需(2,0,0),当前可用资源(2,3,2)可以满足,P4完成后释放资源,此时可用资源变为(2,3,3)。
此时,仍无法满足P2的需求,所以不存在一个安全序列能让所有进程顺利完成。
综上,答案选 D。
35.【2012 统考真题】假设 5 个进程P0,P1,P2,P3,P4共享三类资源R1,R2,R3,这些资源总数分别为 18, 6, 22。T0时刻的资源分配情况如下表所示,此时存在的一个安全序列是( )。
A. P0,P2,P4,P1,P3
B. P1,P0,P3,P4,P2
C. P2,P1,P0,P3,P4
D. P3,P4,P2,P1,P0
- D
首先求得各进程的需求矩阵Need与可利用资源向量Available:
|------|------------------------|
| 进程名 | Need(R1,R2,R3) |
| P0 | 2,3,7 |
| P1 | 1,3,3 |
| P2 | 0,0,6 |
| P3 | 2,2,1 |
| P4 | 1,1,0 |
| 资源类型 | Available(R1,R2,R3) |
| | 2,3,3 |比较Need和Available发现,初始时进程P1与P3可满足需求,排除选项 A、C。尝试给P1分配资源时,P1完成后Available将变为(6,3,6),无法满足P0的需求,排除选项 B。尝试给P3分配资源时,P3完成后Available将变为(4,3,7),该向量能满足其他所有进程的需求。因此以P3开头的所有序列都是安全序列。
36.【2013 统考真题】下列关于银行家算法的叙述中,正确的是( )。
A. 银行家算法可以预防死锁
B. 当系统处于安全状态时,系统中一定无死锁进程
C. 当系统处于不安全状态时,系统中一定会出现死锁进程
D. 银行家算法破坏了死锁必要条件中的 "请求和保持" 条件
- B
银行家算法是用于避免死锁的算法,而不是预防死锁,选项 A 错误。
当系统处于安全状态时,意味着存在一个安全序列,按照这个序列可以为各个进程分配资源,使它们都能顺利完成,所以系统中一定无死锁进程,选项 B 正确。
当系统处于不安全状态时,只是说明可能会进入死锁状态,但不一定会出现死锁进程,选项 C 错误。
银行家算法并没有破坏死锁必要条件中的 "请求和保持" 条件,它是通过在资源分配前进行安全性检查来避免系统进入不安全状态,从而避免死锁,选项 D 错误。
37.【2014 统考真题】某系统有n台互斥使用的同类设备,三个并发进程分别需要 3, 4, 5 台设备,可确保系统不发生死锁的设备数n最小为( )。
A. 9 B. 10 C. 11 D. 12
- B
根据死锁公式,当资源数量大于各个进程所需资源数 - 1 的总和时,不发生死锁,三个进程分别需要 3, 4, 5 台设备,即当资源数量大于(3−1)+(4−1)+(5−1)=9时,不发生死锁。而当系统中只有 9 台设备时,第一个进程分配 2 台,第二个进程分配 3 台,第三个进程分配 4 台,这种情况下,三个进程均无法继续执行下去,发生死锁。当系统再增加 1 台设备,最后 1 台设备分配给任意一个进程都可以顺利执行完成,因此保证系统不发生死锁的最小设备数为 10。
38.【2015 统考真题】若系统S1采用死锁避免方法,S2采用死锁检测方法。下列叙述中,正确的是( )。
I. S1会限制用户申请资源的顺序,而S2不会
II. S1需要进程运行所需的资源总量信息,而S2不需要
III. S1不会给可能导致死锁的进程分配资源,而S2会
A. 仅 I、II B. 仅 II、III C. 仅 I、III D. I、II、III
- B
死锁的处理采用三种策略:死锁预防、死锁避免、死锁检测和解除。
死锁预防采用破坏产生死锁的 4 个必要条件中的一个或几个来防止发生死锁。其中之一的 "破坏循环等待条件",一般采用顺序资源分配法,即限制了用户申请资源的顺序,因此 I 的前半句属于死锁预防的范畴。此外,银行家算法虽然会通过检测是否存在安全序列来判断申请资源的请求是否合法,但安全序列并不是唯一的,也不是固定的,它只是一种可能的分配方案,而不是一种必须遵循的规则,银行家算法更没有给出固定的申请资源的顺序,因此 I 错误。
银行家算法是最著名的死锁避免算法,其中的最大需求矩阵 Max 定义了每个进程对 m 类资源的最大需求量,系统在执行安全性算法中都会检查此次资源试分配后,系统是否处于安全状态,若不安全则将本次的试探分配作废。在死锁的检测和解除中,系统为进程分配资源时不采取任何措施,但提供死锁检测和解除的手段,一旦检测到系统发生死锁,就立即采取相应的措施来解除死锁,因此不用关心进程所需的总资源量。选项 II、III 正确。
39.【2016 统考真题】系统中有 3 个不同的临界资源R1、R2和R3,被 4 个进程P1、P2、P3、P4共享。各进程对资源的需求为:P1申请R1和R2,P2申请R2和R3,P3申请R1和R3,P4申请R2。若系统出现死锁,则处于死锁状态的进程数至少是( )。
A. 1 B. 2 C. 3 D. 4
- C
对于本题,需先画出如下所示的资源分配图。若系统出现死锁,则必然出现循环等待的情况。
从图中可以看出,若出现循环等待的情况,则至少有P1、P2、P3三个进程在循环等待环中,在该图中不可能出现两个进程发生循环等待的情况。现在考察P1、P2、P3三个进程形成环路的情况,若此时P1、P2、P3三个进程分别拥有R1、R2和R3,则会形成P1等待P2释放R2,P2等待P3释放R3,P3等待P1释放R1的循环等待情况。P1、P2、P3三个进程分别拥有R2、R3和R1的情况的分析类似。以上两种情况都会形成循环等待情况,至少有三个进程陷入死锁状态。若P4事先已获取R2,成功运行,则死锁进程数为 3;若P4尚未获取R2,未运行,则死锁进程数为 4。因此,若系统出现死锁,则处于死锁状态的进程至少是3个。
40.【2018 统考真题】假设系统中有 4 个同类资源,进程P1、P2和P3需要的资源数分别为 4, 3 和 1,P1、P2和P3已申请到的资源数分别为 2, 1 和 0,则执行安全性检测算法的结果是( )。
A. 不存在安全序列,系统处于不安全状态
B. 存在多个安全序列,系统处于安全状态
C. 存在唯一安全序列P3,P1,P2,系统处于安全状态
D. 存在唯一安全序列P3,P2,P1,系统处于安全状态
- A
由题意可知,仅剩最后一个同类资源,若将其分给P1或P2,则均无法正常执行;若分给P3,则P3正常执行完成后,释放的这一个资源仍无法使P1、P2正常执行,因此不存在安全序列。
41.【2019 统考真题】下列关于死锁的叙述中,正确的是( )。
I. 可以通过剥夺进程资源解除死锁
II. 死锁的预防方法能确保系统不发生死锁
III. 银行家算法可以判断系统是否处于死锁状态
IV. 当系统出现死锁时,必然有两个或两个以上的进程处于阻塞态
A. 仅 II、III B. 仅 I、II、IV C. 仅 I、II、III D. 仅 I、III、IV
- B
剥夺进程资源,将其分配给其他死锁进程,可以解除死锁,选项 I 正确。
死锁预防是死锁处理策略(死锁预防、死锁避免、死锁检测)中最为严苛的一种策略,破坏死锁产生的 4 个必要条件之一,可以确保系统不发生死锁,选项 II 正确。
银行家算法是一种死锁避免算法,用于计算动态资源分配的安全性以避免系统进入死锁状态,不能用于判断系统是否处于死锁,选项 III 错误。
通过简化资源分配图可以检测系统是否为死锁状态,当系统出现死锁时,资源分配图不可完全简化,只有两个或两个以上的进程才会出现 "环" 而不能被简化,选项 IV 正确。
42.【2020 统考真题】某系统中有 A、B 两类资源各 6 个,t时刻的资源分配及需求情况如下表所示。
t时刻安全性检测结果是( )。
A. 存在安全序列P1、P2、P3
B. 存在安全序列P2、P1、P3
C. 存在安全序列P2、P3、P1
D. 不存在安全序列
- B
首先求出需求矩阵:
由Allocation得知当前Available为(1,0)。由需求矩阵可知,初始只能满足P2的需求,选项 A 错误。P2释放资源后Available变为(3,1),此时仅能满足P1的需求,选项 C 错误。P1释放资源后Available变为(5,4),可以满足P3的需求,得到的安全序列为P2,P1,P3,B 正确,选项 D 错误。
43.【2021 统考真题】若系统中有n(n≥2)个进程,每个进程均需要使用某类临界资源 2 个,则系统不会发生死锁所需的该类资源总数至少是( )。
A. 2 B. n C. n+1 D. 2n
- C
考虑极端情况,当临界资源数为n时,每个进程都拥有 1 个临界资源并等待另一个资源,会发生死锁。当临界资源数为n+1时,则n个进程中至少有一个进程可以获得 2 个临界资源,顺利运行完后释放自己的临界资源,使得其他进程也能顺利运行,不会产生死锁。或者,根据死锁公式m>n(r−1),其中m是系统中临界资源的总数,n是并发进程的个数,r是每个进程所需临界资源的个数。若这个不等式成立,则系统不发生死锁。将本题的数据代入,得到m>n(2−1),即只要系统中临界资源的总数至少是n+1,就可避免死锁。
44.【2022 统考真题】系统中有三个进程P0、P1、P2及三类资源 A、B、C。若某时刻系统分配资源的情况如下表所示,则此时系统中存在的安全序列的个数为( )。
A. 1 B. 2 C. 3 D. 4
- B
初始时系统中的可用资源数为<1,3,2>,只能满足P0的需求<0,2,1>,所以安全序列第一个只能是P0,将资源分配给P0后,P0执行完释放所占资源,可用资源数变为<1,3,2>+<2,0,1>=<3,3,3>,此时可用资源数既能满足P1,又能满足P2,可以先分配给P1,P1执行完释放资源再分配给P2;也可以先分配给P2,P2执行完释放资源再分配给P1。所以安全序列可以是①P0、P1、P2或②P0、P2、P1。
二、综合应用题
1.设系统中有下述解决死锁的方法:
1)银行家算法。
2)检测死锁,终止处于死锁状态的进程,释放该进程占有的资源。
3)资源预分配。
简述哪种办法允许最大的并发性,即哪种办法允许更多的进程无等待地向前推进。请按 "并发性" 从大到小对上述三种办法排序。
- 【解答】
死锁在系统中不可能完全消灭,但我们要尽可能地减少死锁的发生。对死锁的处理有 4 种方法:忽略、检测与恢复、避免和预防,每种方法对死锁的处理从宽到严,同时系统并发性由大到小。这里银行家算法属于避免死锁,资源预分配属于预防死锁。
死锁检测方法可以获得最大的并发性。并发性排序:死锁检测方法、银行家算法、资源预分配法。
2.某银行计算机系统要实现一个电子转账系统,基本业务流程是:首先对转出方和转入方的账户进行加锁,然后进行转账业务,最后对转出方和转入方的账户进行解锁。若不采取任何措施,系统会不会发生死锁?为什么?请设计一个能够避免死锁的办法。
- 【解答】
系统会死锁。因为对两个账户进行加锁操作是可以分割进行的,若此时有两个用户同时进行转账,P1先对账户A进行加锁,再申请账户B;P2先对账户B进行加锁,再申请账户A,此时产生死锁。解决的办法是:可以采用资源顺序分配法对A、B账户进行编号,用户转账时只能按照编号由小到大进行加锁;也可采用资源预分配法,要求用户在使用资源前将所有资源一次性申请到。
3.设有进程P1和进程P2并发执行,都需要使用资源R1和R2,使用资源的情况见下表。
试判断是否会发生死锁,并解释和说明产生死锁的原因与必要条件。
- 【解答】
这段程序在不同的运行推进速度下,可能产生死锁。例如,进程P1先申请资源R1,得到资源R1,然后进程P2申请资源R2,得到资源R2,进程P1又申请资源R2,因资源R2已分配,使得进程P1阻塞。进程P1和进程P2都因申请不到资源而形成死锁。若改变进程的运行顺序,则这两个进程就不会出现死锁现象。
产生死锁的原因可归结为两点:
1)竞争资源。
2)进程推进顺序非法。
产生死锁的必要条件:
1)互斥条件。
2)请求并保持条件。
3)不剥夺条件。
4)环路等待条件。
4.系统有同类资源m个,供n个进程共享,若每个进程对资源的最大需求量为k,试问:当m,n,k的值分别为下列情况时(见下表),是否会发生死锁?
- 【解答】
不发生死锁要求,必须保证至少有一个进程得到所需的全部资源并执行完毕,m≥n(k−1)+1时,一定不会发生死锁。
|----|----|---|---|-------|-------------|
| 序号 | m | n | k | 是否会死锁 | 说明 |
| 1 | 6 | 3 | 3 | 可能会 | 6<3(3−1)+1 |
| 2 | 9 | 3 | 3 | 不会 | 9>3(3−1)+1 |
| 3 | 13 | 6 | 3 | 不会 | 13=6(3−1)+1 |5.有三个进程P1、P2和P3并发工作。进程P1需要资源S3和资源S1;进程P2需要资源S2和资源S1;进程P3需要资源S3和资源S2。问:
1)若对资源分配不加限制,会发生什么情况?为什么?
2)为保证进程正确运行,应采用怎样的分配策略?列出所有可能的方法。
- 【解答】
1)可能发生死锁。满足发生死锁的 4 大条件,例如,P1占有S1申请S3,P2占有S2申请S1,P3占有S3申请S2。
2)可有以下几种答案:
A. 采用静态分配:因为执行前已获得所需的全部资源,所以不会出现占有资源又等待别的资源的现象(或不会出现循环等待资源的现象)。
B. 采用按序分配:不会出现循环等待资源的现象。
C. 采用银行家算法:因为在分配时,保证了系统处于安全状态。
6.某系统有R1、R2和R3共三种资源,在T0时刻P1、P2、P3和P4这四个进程对资源的占用和需求情况见下表,此时系统的可用资源向量为 (2, 1, 2)。试问:
1)系统是否处于安全状态?若安全,则请给出一个安全序列。
2)若此时进程P1和进程P2均发出资源请求向量 Request (1, 0, 1),为了保证系统的安全性,应如何分配资源给这两个进程?说明所采用策略的原因。
3)若 2)中两个请求立即得到满足后,系统此刻是否处于死锁状态?
|-----|---------|-----|-----|---------|-----|-----|
| 进程名 | 资源情况 | | | | | |
| | 最大资源需求量 | | | 已分配资源数量 | | |
| | R1 | R2 | R3 | R1 | R2 | R3 |
| P1 | 3 | 2 | 2 | 1 | 0 | 0 |
| P2 | 6 | 1 | 3 | 4 | 1 | 1 |
| P3 | 3 | 1 | 4 | 2 | 1 | 1 |
| P4 | 4 | 2 | 2 | 0 | 0 | 2 |
- 【解答】
1)利用安全性算法对T0时刻的资源分配情况进行分析,可得到如下表所示的安全性检测情况。可以看出,此时存在一个安全序列{P2,P3,P4,P1},所以该系统是安全的。
此处要注意,一般大多数题目中的安全序列并不唯一。
2)若此时P1发出资源请求Request1(1,0,1),则按银行家算法进行检查:
Request1(1,0,1)≤Need1(2,2,2)
Request1(1,0,1)≤Available(2,1,2)
试分配并修改相应数据结构,由此形成的进程P1请求资源后的资源分配情况见下表。
再利用安全性算法检查系统是否安全,可用资源Available(1,1,1)已不能满足任何进程,系统进入不安全状态,此时系统不能将资源分配给进程P1。
若此时进程P2发出资源请求Request2(1,0,1),则按银行家算法进行检查:
Request2(1,0,1)≤Need2(2,0,2)
Request2(1,0,1)≤Available(2,1,2)
试分配并修改相应数据结构,由此形成的进程P2请求资源后的资源分配情况下表:
再利用安全性算法检查系统是否安全,可得到如下表中所示的安全性检测情况。注意表中各个进程对应的 Work + Allocation 向量表示在该进程释放资源之后更新的 Work 向量。
从上表中可以看出,此时存在一个安全序列{P2,P3,P4,P1},因此该状态是安全的,可以立即将进程P2所申请的资源分配给它。
3)若 2)中的两个请求立即得到满足,则此刻系统并未立即进入死锁状态,因为这时所有的进程未提出新的资源申请,全部进程均未因资源请求没有得到满足而进入阻塞态。只有当进程提出资源申请且全部进程都进入阻塞态时,系统才处于死锁状态。
7.考虑某个系统在下表时刻的状态。
|-----|------------|---|---|---|-----|---|---|---|-----------|---|---|---|
| 进程名 | Allocation | | | | Max | | | | Available | | | |
| | A | B | C | D | A | B | C | D | A | B | C | D |
| P0 | 0 | 0 | 1 | 2 | 0 | 0 | 1 | 2 | 1 | 5 | 2 | 0 |
| P1 | 1 | 0 | 0 | 0 | 1 | 7 | 5 | 0 | | | | |
| P2 | 1 | 3 | 5 | 4 | 2 | 3 | 5 | 6 | | | | |
| P3 | 0 | 0 | 1 | 4 | 0 | 6 | 5 | 6 | | | | |使用银行家算法回答下面的问题:
1)Need 矩阵是怎样的?
2)系统是否处于安全状态?如安全,请给出一个安全序列。
3)若从进程P1发来一个请求 (0, 4, 2, 0),这个请求能否立刻被满足?如安全,请给出一个安全序列。
- 【解答】
1)
2)Work向量初始化值 = Available(1,5,2,0)。
系统安全性分析:
因为存在一个安全序列<P0,P2,P1,P3>,所以系统处于安全状态。
3)Request1(0,4,2,0)<Need1(0,7,5,0)
Request1(0,4,2,0)<Available(1,5,2,0)
假设先试着满足进程P1的这个请求,则Available变为(1,1,0,0)。
系统状态变化见下表:
8.假设具有 5 个进程的进程集合P={P0,P1,P2,P3,P4},系统中有三类资源 A, B, C,假设在某时刻有如下状态:
|-----|------------|---|---|-----|---|---|-----------|---|---|
| 进程名 | Allocation | | | Max | | | Available | | |
| | A | B | C | A | B | C | A | B | C |
| P0 | 0 | 0 | 3 | 0 | 0 | 4 | 1 | 4 | 0 |
| P1 | 1 | 0 | 0 | 1 | 7 | 5 | | | |
| P2 | 1 | 3 | 5 | 2 | 3 | 5 | | | |
| P3 | 0 | 0 | 2 | 0 | 6 | 4 | | | |
| P4 | 0 | 0 | 1 | 0 | 6 | 5 | | | |当前系统是否处于安全状态?若系统中的可利用资源 Available 为 (0, 6, 2),系统是否安全?若系统处在安全状态,请给出安全序列;若系统处在非安全状态,简要说明原因。
- 【解答】
1)根据Need矩阵可知,初始Work等于Available为(1,4,0),可以满足进程P2的需求;进程P2结束后释放资源,Work为(2,7,5),可以满足P0,P1,P3和P4中任意一个进程的需求,所以系统不会出现死锁,当前处于安全状态。
2)若初始Work=Available为(0,6,2),可满足进程P0,P3的需求;这两个进程结束后释放资源,Work为(0,6,7),仅可满足进程P4的需求;P4结束后释放资源,Work为(0,6,8),此时不能满足余下任意一个进程的需求,系统出现死锁,因此当前系统处在非安全状态。
注意:
在银行家算法中,当实际计算分析系统安全状态时,并不需要逐个进程进行。如本题中,在情况 1)下,当计算到进程P2结束并释放资源时,系统当前空闲资源可满足余下任意一个进程的最大需求量,这时已经不需要考虑进程的执行顺序。系统分配任意一个进程所需的最大需求资源,在其执行结束释放资源后,系统当前空闲资源会增加,所以余下的进程仍然可以满足最大需求量。因此,在这里可以直接判断系统处于安全状态。在情况 2)下,系统当前可满足进程P0,P3的需求,所以可以直接让系统推进到P0,P3执行完并释放资源后的情形,这时系统出现死锁;因为此时是系统空闲资源所能达到的最大值,所以按照其他方式推进,系统必然还是出现死锁。因此,在计算过程中,将每步中可满足需求的进程作为一个集合,同时执行并释放资源,可以简化银行家算法的计算。
2.5 本章疑难点
1. 进程与程序的区别与联系
1)进程是程序及其数据在计算机上的一次运行活动,是一个动态的概念。进程的运行实体是程序,离开程序的进程没有存在的意义。从静态角度看,进程是由程序、数据和进程控制块(PCB)三部分组成的。而程序是一组有序的指令集合,是一种静态的概念。
2)进程是程序的一次执行过程,它是动态地创建和消亡的,具有一定的生命周期,是暂时存在的;而程序则是一组代码的集合,是永久存在的,可长期保存。
3)一个进程可以执行一个或几个程序,一个程序也可构成多个进程。进程可创建进程,而程序不可能形成新的程序。
4)进程与程序的组成不同。进程的组成包括程序、数据和 PCB。
2. 银行家算法的工作原理
银行家算法的主要思想是避免系统进入不安全状态。在每次进行资源分配时,它首先检查系统是否有足够的资源满足要求,若有则先进行试分配,并对分配后的新状态进行安全性检查。若新状态安全,则正式分配上述资源,否则拒绝分配上述资源。这样,它保证系统始终处于安全状态,从而避免了死锁现象的发生。
3. 进程同步、互斥的区别和联系
并发进程的执行会产生相互制约的关系:一种是进程之间竞争使用临界资源,只能让它们逐个使用,这种现象称为互斥,是一种竞争关系;另一种是进程之间协同完成任务,在关键点上等待另一个进程发来的消息,以便协同一致,是一种协作关系。
第 3 章 内存管理
【考纲内容】
(一)内存管理基础
内存管理概念:逻辑地址与物理地址空间,地址变换,内存共享,内存保护,内存分配与回收
连续分配管理方式;页式管理;段式管理;段页式管理
(二)虚拟内存管理
虚拟内存基本概念;请求页式管理;页框分配与回收;页置换算法
内存映射文件(Memory-Mapped Files);虚拟存储器性能的影响因素及改进方式
【复习提示】
内存管理和进程管理是操作系统的核心内容,需要重点复习。本章围绕分页机制展开:通过分页管理方式在物理内存大小的基础上提高内存的利用率,再进一步引入请求分页管理方式,实现虚拟内存,使内存脱离物理大小的限制,从而提高处理器的利用率。
3.1 内存管理概念
在学习本节时,请读者思考以下问题:
1)为什么要进行内存管理?
2)多级页表解决了什么问题?又会带来什么问题?
在学习经典的管理方法前,同样希望读者先思考,自己给出一些内存管理的想法,并在学习过程中和经典方案进行比较。注意本节给出的内存管理是循序渐进的,后一种方法通常会解决前一种方法的不足。希望读者多多思考,比较每种方法的异同,着重掌握页式管理。
3.1.1 内存管理的基本原理和要求
内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件技术一直在飞速发展,内存容量也在不断增大,但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主存,因此操作系统必须对内存空间进行合理的划分和有效的动态分配。操作系统对内存的划分和动态分配,就是内存管理的概念。
有效的内存管理在多道程序设计中非常重要,它不仅可以方便用户使用存储器、提高内存利用率,还可以通过虚拟技术从逻辑上扩充存储器。内存管理的主要功能有:
- 内存空间的分配与回收。由操作系统负责内存空间的分配和管理,记录内存的空闲空间、内存的分配情况,并回收已结束进程所占用的内存空间。
- 地址转换。程序的逻辑地址与内存中的物理地址不可能一致,因此存储管理必须提供地址变换功能,将逻辑地址转换成相应的物理地址。
- 内存空间的扩充。利用虚拟存储技术从逻辑上扩充内存。
- 内存共享。指允许多个进程访问内存的同一部分。例如,多个合作进程可能需要访问同一块数据,因此必须支持对内存共享区域进行受控访问。
- 存储保护。保证各个进程在各自的存储空间内运行,互不干扰。
在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。
1. 逻辑地址与物理地址
命题追踪 进程虚拟地址空间的特点(2023)
编译后,每个目标模块都从 0 号单元开始编址,这称为该目标模块的相对地址(或逻辑地址)。当链接程序将各个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从 0 号单元开始编址的逻辑地址空间(或虚拟地址空间),对于 32 位系统,逻辑地址空间的范围为 0~232−1。进程在运行时,看到和使用的地址都是逻辑地址。用户程序和程序员只需知道逻辑地址,而内存管理的具体机制则是完全透明的。不同进程可以有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。
物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据,最后都要通过物理地址从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位。
操作系统通过内存管理部件(MMU)将进程使用的逻辑地址转换为物理地址。进程使用虚拟内存空间中的地址,操作系统在相关硬件的协助下,将它 "转换" 成真正的物理地址。逻辑地址通过页表映射到物理内存,页表由操作系统维护并被处理器引用。
2. 程序的链接与装入
创建进程首先要将程序和数据装入内存。将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤:
命题追踪 编译、链接和装入阶段的工作内容(2011)
- 编译。由编译程序将用户源代码编译成若干目标模块。
- 链接。由链接程序将编译后形成的一组目标模块,以及它们所需的库函数链接在一起,形成一个完整的装入模块。
- 装入。由装入程序将装入模块装入内存运行。
将用户程序变为可在内存中执行的程序的步骤如图 3.1 所示。
图 3.1 将用户程序变为可在内存中执行的程序的步骤
将一个装入模块装入内存时,有以下三种装入方式。
(1)绝对装入
绝对装入方式只适用于单道程序环境。在编译时,若知道程序将放到内存的哪个位置,则编译程序将产生绝对地址的目标代码。装入程序按照装入模块的地址,将程序和数据装入内存。程序中的逻辑地址与实际内存地址完全相同,因此不需对程序和数据的地址进行修改。
程序中使用的绝对地址,可在编译或汇编时给出,也可由程序员直接赋予。而通常情况下在程序中采用的是符号地址,编译或汇编时再转换为绝对地址。
(2)可重定位装入
可重定位装入也称静态重定位。经过编译、链接后的装入模块的始址(起始地址)通常都是从 0 开始的,程序中使用的指令和数据的地址都是相对于始址而言的逻辑地址。可根据内存的当前情况,将装入模块装入内存的适当位置。在装入时对目标程序中的相对地址的修改过程称为重定位,地址转换通常是在进程装入时一次完成的,如图 3.2 (a) 所示。
当一个作业装入内存时,必须给它分配要求的全部内存空间,若没有足够的内存,则无法装入。作业一旦进入内存,整个运行期间就不能在内存中移动,也不能再申请内存空间。
(3)动态运行时装入
动态运行时装入也称动态重定位。程序若要在内存中发生移动,则要采用动态的装入方式。装入程序将装入模块装入内存后,并不会立即将装入模块中的相对地址转换为绝对地址,而是将这种地址转换推迟到程序真正要执行时才进行。因此,装入内存后的所有地址均为相对地址。这种方式需要一个重定位寄存器(存放装入模块的起始位置)的支持,如图 3.2 (b) 所示。
动态重定位的优点:可以将程序分配到不连续的存储区;在程序运行前只需装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享。

对目标模块进行链接时,根据链接的时间不同,分为以下三种链接方式。
(1)静态链接
在程序运行之前,先将各目标模块及它们所需的库函数链接成一个完整的装入模块,以后不再拆开。将几个目标模块装配成一个装入模块时,需要解决两个问题:①修改相对地址,编译后的所有目标模块都是从 0 开始的相对地址,当链接成一个装入模块时要修改相对地址。②变换外部调用符号,将每个模块中所用的外部调用符号也都变换为相对地址。
(2)装入时动态链接
将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的方式。其优点是便于修改和更新,便于实现对目标模块的共享。
(3)运行时动态链接
在程序执行中需要某目标模块时,才对它进行链接。凡在程序执行中未用到的目标模块,都不会被调入内存和链接到装入模块上。其优点是能加快程序的装入过程,还可节省内存空间。
3. 进程的内存映像
不同于存放在硬盘上的可执行程序文件,当一个程序调入内存运行时,就构成了进程的内存映像。一个进程的内存映像一般有几个要素:
- 代码段:即程序的二进制代码,代码段是只读的,可以被多个进程共享。
- 数据段:即程序运行时加工处理的对象,包括全局变量和静态变量。
- 进程控制块(PCB):存放在系统区。操作系统通过 PCB 来控制和管理进程。
- 堆:用来存放动态分配的变量。通过调用 malloc 函数动态地向高地址分配空间。
- 栈:用来实现函数调用。从用户空间的最大地址往低地址方向增长。
代码段和数据段在程序调入内存时就指定了大小,而堆和栈不一样。当调用像 malloc 和 free 这样的 C 标准库函数时,堆可以在运行时动态地扩展和收缩。用户栈在程序运行期间也可以动态地扩展和收缩,每次调用一个函数,栈就会增长;从一个函数返回时,栈就会收缩。
图 3.3 是一个进程在内存中的映像。其中,共享库用来存放进程用到的共享函数库代码,如 printf () 函数等。在只读代码段中,.init 是程序初始化时调用的_init 函数;.text 是用户程序的机器代码;.rodata 是只读数据。在读 / 写数据段中,.data 是已初始化的全局变量和静态变量;.bss 是未初始化及所有初始化为 0 的全局变量和静态变量。

4. 内存保护
命题追踪 分区分配内存保护的措施(2009)
确保每个进程都有一个单独的内存空间。内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。内存保护可采取两种方法:
1)在 CPU 中设置一对上、下限寄存器,存放用户进程在主存中的下限和上限地址,每当 CPU 要访问一个地址时,分别和两个寄存器的值相比,判断有无越界。
2)采用重定位寄存器(也称基地址寄存器)和界地址寄存器(也称限长寄存器)进行越界检查。重定位寄存器中存放的是进程的起始物理地址,界地址寄存器中存放的是进程的最大逻辑地址。内存管理部件将逻辑地址与界地址寄存器进行比较,若未发生地址越界,则加上重定位寄存器的值后映射成物理地址,再送交内存单元,如图 3.4 所示。

实现内存保护需要重定位寄存器和界地址寄存器,因此要注意两者的区别。重定位寄存器是用来 "加" 的,逻辑地址加上重定位寄存器中的值就能得到物理地址;界地址寄存器是用来 "比" 的,通过比较界地址寄存器中的值与逻辑地址的值来判断是否越界。
加载重定位寄存器和界地址寄存器时必须使用特权指令,只有操作系统内核才可以加载这两个存储器。这种方案允许操作系统内核修改这两个寄存器的值,而不允许用户程序修改。
5. 内存共享
并不是所有的进程内存空间都适合共享,只有那些只读的区域才可以共享。可重入代码也称纯代码,是一种允许多个进程同时访问但不允许被任何进程修改的代码。但在实际执行时,也可以为每个进程配以局部数据区,将在执行中可能改变的部分复制到该数据区,这样,程序在执行时只需对该私有数据区中的内存进行修改,并不去改变共享的代码。
下面用一个例子来说明内存共享的实现方式。考虑一个可以同时容纳 40 个用户的多用户系统,他们同时执行一个文本编辑程序,若该程序有 160KB 代码区和 40KB 数据区,则共需 8000KB 的内存空间来支持 40 个用户。若 160KB 代码是可分享的纯代码,则不论是在分页系统中还是在分段系统中,整个系统只需保留一份副本即可,此时所需的内存空间仅为 40KB×40 + 160KB = 1760KB。对于分页系统,假设页面大小为 4KB,则代码区占用 40 个页面、数据区占用 10 个页面。为实现代码共享,应在每个进程的页表中都建立 40 个页表项,它们都指向共享代码区的物理页号。此外,每个进程还要为自己的数据区建立 10 个页表项,指向私有数据区的物理页号。对于分段系统,由于是以段为分配单位的,不管该段有多大,都只需为该段设置一个段表项(指向共享代码段始址,以及段长 160KB)。由此可见,段的共享非常简单易行。
此外,在第 2 章中我们介绍过基于共享内存的进程通信,由操作系统提供同步互斥工具。在本章的后面,还将介绍一种内存共享的实现 ------ 内存映射文件。
6. 内存分配与回收
存储管理方式随着操作系统的发展而发展。在操作系统由单道向多道发展时,存储管理方式便由单一连续分配发展为固定分区分配。为了能更好地适应不同大小的程序要求,又从固定分区分配发展到动态分区分配。为了更好地提高内存的利用率,进而从连续分配方式发展到离散分配方式 ------ 页式存储管理。引入分段存储管理的目的,主要是满足用户在编程和使用方面的要求,其中某些要求是其他几种存储管理方式难以满足的。
3.1.2 连续分配管理方式
连续分配方式是指为一个用户程序分配一个连续的内存空间,譬如某用户需要 100MB 的内存空间,连续分配方式就在内存空间中为用户分配一块连续的 100MB 空间。连续分配方式主要包括单一连续分配、固定分区分配和动态分区分配。
1. 单一连续分配
在单一连续分配方式中,内存被分为系统区和用户区,系统区仅供操作系统使用,通常在低地址部分;用户区内存中仅有一道用户程序,即用户程序独占整个用户区。
这种方式的优点是简单、无外部碎片;不需要进行内存保护,因为内存中永远只有一道程序。缺点是只能用于单用户、单任务的操作系统;有内部碎片;内存的利用率极低。
2. 固定分区分配
固定分区分配是最简单的一种多道程序存储管理方式,它将用户内存空间划分为若干固定大小的分区,每个分区只装入一道作业。当有空闲分区时,便可再从外存的后备作业队列中选择适当大小的作业装入该分区,如此循环。在划分分区时有两种不同的方法。
- 分区大小相等。程序太小会造成浪费,程序太大又无法装入,缺乏灵活性。
- 分区大小不等。划分为多个较小的分区、适量的中等分区和少量大分区。
为了便于分配和回收,建立一张分区使用表,通常按分区大小排队,各表项包括对应分区的始址、大小及状态(是否已分配),如图 3.5 所示。分配内存时,便检索该表,以找到一个能满足要求且尚未分配的分区分配给装入程序,并将对应表项的状态置为 "已分配";若找不到这样的分区,则拒绝分配。回收内存时,只需将对应表项的状态置为 "未分配" 即可。

这种方式存在两个问题:①程序太大而放不进任何一个分区;②当程序小于固定分区大小时,也要占用一个完整的内存分区,这样分区内部就存在空间浪费,这种现象称为内部碎片。固定分区方式无外部碎片,但不能实现多进程共享一个主存区,所以内存的利用率低。
3. 动态分区分配
(1)动态分区分配的基本原理
动态分区分配也称可变分区分配,是指在进程装入内存时,根据进程的实际需要,动态地为之分配内存,并使分区的大小正好适合进程的需要。因此,系统中分区的大小和数量是可变的。
如图 3.6 所示,系统有 64MB 内存空间,其中低 8MB 固定分配给操作系统,其余为用户可用内存。开始时装入前三个进程,它们分别分配到所需的空间后,内存仅剩 4MB,进程 4 无法装入。在某个时刻,内存中没有一个就绪进程,CPU 出现空闲,操作系统就换出进程 2,换入进程 4。由于进程 4 比进程 2 小,这样在主存中就产生了一个 6MB 的内存块。之后 CPU 又出现空闲,需要换入进程 2,而主存无法容纳进程 2,操作系统就换出进程 1,换入进程 2。
动态分区在开始时是很好的,但是随着时间的推移,内存中会产生越来越多的小内存块,内存的利用率也随之下降。这些小内存块被称为外部碎片,它存在于所有分区的外部,与固定分区中的内部碎片正好相对。外部碎片可通过紧凑技术来克服,即操作系统不时地对进程进行移动和整理。但是,这需要动态重定位寄存器的支持,且相对费时。紧凑过程实际上类似于 Windows 系统中的磁盘碎片整理程序,只不过后者是对外存空间的紧凑。

命题追踪 动态分区分配的内存回收方法(2017)
在动态分区分配中,与固定分区分配类似,设置一张空闲分区链(表),可以按地址排序。分配内存时,检索空闲分区链,找到所需的分区,若其大小大于请求大小,则从该分区中按请求大小分割一块空间分配给装入进程(若剩余部分小到不足以划分,则不需要分割),余下部分仍然留在空闲分区链中。回收内存时,系统根据回收分区的始址,从空闲分区链中找到相应的插入点,此时可能出现四种情况:①回收区与插入点的前一空闲分区相邻,此时将这两个分区合并,并修改前一分区表项的大小为两者之和;②回收区与插入点的后一空闲分区相邻,此时将这两个分区合并,并修改后一分区表项的大小为两者之和;③回收区同时与插入点的前、后两个分区相邻,此时将这三个分区合并,修改前一分区表项的大小为三者之和,并取消后一分区表项;④回收区没有相邻的空闲分区,此时应该为回收区新建一个表项,填写始址和大小,并插入空闲分区链。
以上三种内存分区管理方法有一个共同特点,即用户程序在主存中都是连续存放的。
(2)基于顺序搜索的分配算法
将作业装入主存时,需要按照一定的分配算法从空闲分区链(表)中选出一个分区,以分配给该作业。按分区检索方式,可分为顺序分配算法和索引分配算法。顺序分配算法是指依次搜索空闲分区链上的空闲分区,以寻找一个大小满足要求的分区,顺序分配算法有以下四种。
命题追踪 各种动态分区分配算法的特点(2019、2024)
- 首次适应(First Fit)算法 :空闲分区按地址递增的次序排列。每次分配内存时,顺序查找,找到第一个能满足大小的空闲分区,分配给作业。首次适应算法保留了内存高地址部分的大空闲分区,有利于后续大作业的装入。但它会使内存低地址部分出现许多小碎片,而每次分配查找时都要经过这些分区,因此增加了开销。
- 邻近适应(Next Fit)算法 :也称循环首次适应算法,由首次适应算法演变而成。不同之处是,分配内存时从上次查找结束的位置开始继续查找。邻近适应算法试图解决该问题。它让内存低、高地址部分的空闲分区以同等概率被分配,划分为小分区,导致内存高地址部分没有大空闲分区可用。通常比首次适应算法更差。
命题追踪 最佳适应算法的分配过程(2010)
- 最佳适应(Best Fit)算法 :空闲分区按容量递增的次序排列。每次分配内存时,顺序查找,找到第一个能满足大小的空闲分区,即最小的空闲分区,分配给作业。最佳适应算法虽然称为最佳,能更多地留下大空闲分区,但性能通常很差,因为每次分配会留下越来越多很小的难以利用的内存块,进而产生最多的外部碎片。
- 最坏适应(Worst Fit)算法 :空闲分区按容量递减的次序排列。每次分配内存时,顺序查找,找到第一个能满足要求的空闲分区,即最大的空闲分区,从中分割一部分空间给作业。与最佳适应算法相反,最坏适应算法选择最大的空闲分区,这看起来最不容易产生碎片,但是把最大的空闲分区分开,会很快导致没有大空闲分区可用,因此性能也很差。
综合来看,首次适应算法的开销小,性能最好,回收分区也不需要对空闲分区重新排序。
(3)基于索引搜索的分配算法
当系统很大时,空闲分区链可能很长,此时采用顺序分配算法可能很慢。因此,在大、中型系统中往往采用索引分配算法。索引分配算法的思想是,根据其大小对空闲分区分类,对于每类(大小相同)空闲分区,单独设立一个空闲分区链,并设置一张索引表来管理这些空闲分区链。当为进程分配空间时,在索引表中查找所需空间大小对应的表项,并从中得到对应的空闲分区链的头指针,从而获得一个空闲分区。索引分配算法有以下三种。
- 1)快速适应算法:空闲分区的分类根据进程常用的空间大小进行划分。分配过程分为两步:①首先根据进程的长度,在索引表中找到能容纳它的最小空闲分区链表;②然后从链表中取下第一块进行分配。优点是查找效率高、不会产生内存碎片;缺点是回收分区时,需要有效地合并分区,算法比较复杂,系统开销较大。
命题追踪 伙伴关系的概念(2024)
- 2)伙伴系统:规定所有分区的大小均为 2 的 k 次幂(k 为正整数)。当需要为进程分配大小为 n 的分区时(2k−1<n⩽2k),在大小为2k的空闲分区链中查找。若找到,则将该空闲分区分配给进程。否则,表示大小为2k的空闲分区已耗尽,需要在大小为2k+1的空闲分区链中继续查找。若存在大小为2k+1的空闲分区,则将其等分为两个分区,这两个分区称为一对伙伴,其中一个用于分配,而将另一个加入大小为2k的空闲分区链。若不存在,则继续查找,直至找到为止。回收时,需要要将相邻的空闲伙伴分区合并成更大的分区。
- 哈希算法:根据空闲分区链表的分布规律,建立哈希函数,构建一张以空闲分区大小为关键字的哈希表,每个表项记录一个对应空闲分区链的头指针。分配时,根据所需分区大小,通过哈希函数计算得到哈希表中的位置,从中得到相应的空闲分区链表。
在连续分配方式中,我们发现,即使内存有超过 1GB 的空闲空间,但若没有连续的 1GB 空间,则需要 1GB 空间的作业仍然是无法运行的;但若采用非连续分配方式,则作业所要求的 1GB 内存空间可以分散地分配在内存的各个区域,当然,这也需要额外的空间去存储它们(分散区域)的索引,使得非连续分配方式的存储密度低于连续分配方式。非连续分配方式根据分区的大小是否固定,分为分页存储管理和分段存储管理。在分页存储管理中,又根据运行作业时是否要将作业的所有页面都装入内存才能运行,分为基本分页存储管理和请求分页存储管理。
3.1.3 基本分页存储管理
固定分区会产生内部碎片,动态分区会产生外部碎片,这两种技术对内存的利用率都比较低。我们希望内存的使用能尽量避免碎片的产生,这就引入了分页的思想:将内存空间分为若干固定大小(如 4KB)的分区,称为页框、页帧或物理块。进程的逻辑地址空间也分为与块大小相等的若干区域,称为页或页面。操作系统以页框为单位为各个进程分配内存空间。
从形式上看,分页的方法像是分区相等的固定分区技术,分页管理不产生外部碎片。但它又有本质的不同点:块的大小相对分区要小很多,而且进程也按照块进行划分,进程运行时按块串请主存可用空间并执行。这样,进程只会在为最后一个不完整的块申请一个主存块空间时,才产生主存碎片,所以尽管会产生内部碎片,但这种碎片相对进程来说也是很小的,每个进程平均只产生半个块大小的内部碎片(也称页内碎片)。
1. 分页存储的几个基本概念
1)页面和页面大小:
进程的逻辑地址空间中的每个页面有一个编号,称为页号,从 0 开始;内存空间中的每个页框也有一个编号,称为页框号(或物理块号),也从 0 开始。进程在执行时需要申请内存空间,即要为每个页面分配内存中的可用页框,这就产生了页号和页框号的一一对应。
为方便地址转换,页面大小应是 2 的整数次幂。同时页面大小应该适中,页面太小会使进程的页面数过多,这样页表就会过长,占用大量内存,而且也会增加硬件地址转换的开销,降低页面换入 / 换出的效率;页面过大又会使页内碎片增多,降低内存的利用率。
2)地址结构
命题追踪 分页系统的逻辑地址结构(2009、2010、2013、2015、2017、2024)
某个分页存储管理的逻辑地址结构如图 3.7 所示。

地址结构包含两部分:前一部分为页号 P,后一部分为页内偏移量 W。地址长度为 32 位,其中 0~11 位为页内地址,即每页大小为212B;12~31 位为页号,即最多允许220页。在实际题目中,页号、页内偏移、逻辑地址可能是用十进制数给出的,注意进制之间的转换。
3)页表
为了便于找到进程的每个页面在内存中存放的位置,系统为每个进程建立一张页面映射表,简称页表。进程的每个页面对应一个页表项,每个页表项由页号和块号组成,它记录了页面在内存中对应的物理块号,如图 3.8 所示。进程执行时,通过查找页表,即可找到每页在内存中的物理块号。可见,页表的作用是实现从页号到物理块号的地址映射。

2. 基本地址变换机构
地址变换机构的任务是将逻辑地址转换为内存中的物理地址。地址变换是借助于页表实现的。图 3.9 给出了分页存储管理系统中的地址变换机构。

注意
在页表中,页表项连续存放,因此页号可以是隐含的,不占用存储空间。
为了提高地址变换的速度,在系统中设置一个页表寄存器(PTR),存放页表在内存的始址 F 和页表长度 M。寄存器的造价昂贵,因此在单 CPU 系统中只设置一个页表寄存器。平时,进程未执行时,页表的始址和页表长度存放在本进程的 PCB 中。当进程被调度执行时,才将页表始址和页表长度装入页表寄存器中。设页面大小为 L,逻辑地址 A 到物理地址 E 的变换过程如下(假设逻辑地址、页号、每页的长度都是十进制数):
命题追踪 页式系统的地址变换过程(2013、2021、2024)
命题追踪 页表项地址的计算与分析(2024)
- 根据逻辑地址计算出页号P=A/L、页内偏移量W=A%L。
- 判断页号是否越界,若页号P≥页表长度 M,则产生越界中断,否则继续执行。
- 在页表中查询页号对应的页表项,确定页面存放的物理块号。页号 P 对应的页表项地址 = 页表始址 F + 页号 P× 页表项长度,取出该页表项内容 b,即为物理块号。
- 计算物理地址E=bL+W,用物理地址 E 去访存。注意,物理地址 = 页面在内存中的始址 + 页内偏移量,页面在内存中的始址 = 块号 × 块大小(页面大小)。
以上整个地址变换过程均是由硬件自动完成的。例如,若页面大小 L 为 1KB,页号 2 对应的物理块为b=8,计算逻辑地址A=2500的物理地址 E 的过程如下:P=2500/1K=2,W=2500%1K=452,查找到页号 2 对应的物理块的块号为 8,E=8×1024+452=8644。
计算条件用十进制数和用二进制数给出,过程会稍有不同。页式管理只需给出一个整数就能确定对应的物理地址,因为页面大小 L 是固定的。因此,页式管理中地址空间是一维的。
页表项的大小不是随意规定的,而是有所约束的。如何确定页表项的大小?
页表项的作用是找到该页在内存中的位置。以 32 位内存地址空间、按字节编址、一页 4KB 为例,地址空间内一共有2^32B/4KB=2^20页,因此需要log2 2^20=20位才能保证表示范围能容纳所有页面,又因为内存以字节作为编址单位,即页表项的大小≥⌈20/8⌉=3B。所以在这个条件下,为了保证页表项能够指向所有页面,页表项的大小应大于或等于 3B。当然,也可以选择更大的页表项,让一个页面能够正好容纳整数个页表项,或便于增加一些其他信息。
下面讨论分页管理方式存在的两个主要问题:①每次访存操作都需要进行逻辑地址到物理地址的转换,地址转换过程必须足够快,否则访存速度会降低;②每个进程引入页表,用于存储映射机制,页表不能太大,否则内存利用率会降低。