死锁预防

死锁预防是指通过设计特定的资源分配策略,破坏死锁产生的四个必要条件中的至少一个,从而从根本上避免死锁的发生。与后续的“死锁避免”“死锁检测”不同,死锁预防不需要动态判断系统状态,而是通过预先制定规则,强制阻止死锁条件的形成。其核心思想是:“防患于未然”,在进程申请资源的初期就切断死锁可能的形成路径。

1. 破坏互斥条件

互斥条件是指资源必须被进程独占使用。要破坏这一条件,需通过资源虚拟化或转换,使原本需要互斥访问的资源可以被多个进程同时共享。

(1)实现方式:资源共享化

最典型的方法是采用SPOOLing技术(假脱机技术),将独占设备(如打印机、扫描仪)转换为共享的虚拟设备。例如:

  • 打印机原本是独占设备,一个进程使用时其他进程必须等待;
  • 通过SPOOLing系统,所有进程的打印请求先被存入磁盘缓冲区(虚拟打印机),由系统统一调度打印。此时,进程访问的是磁盘上的共享缓冲区,而非物理打印机,从而打破了“互斥使用”的限制。
(2)适用范围与局限性

这种方法仅适用于可被虚拟化的资源(如外设),但对多数资源(如内存、文件排他锁)无效——这些资源的特性决定了必须互斥访问(如多个进程同时修改同一文件会导致数据混乱)。因此,破坏互斥条件的应用场景有限。

2. 破坏持有并等待条件

持有并等待条件是指进程“持有部分资源同时等待其他资源”。破坏这一条件的关键是阻止进程在持有资源的同时申请新资源,主要有两种实现策略:

(1)策略一:进程启动时一次性申请所有所需资源

要求进程在开始执行前,必须一次性声明所需的全部资源。系统只有在满足进程所有资源请求后,才会将资源分配给它;若有任何一种资源无法满足,进程需等待,且在等待期间不能持有任何资源。

例如,一个视频编辑进程需要CPU、内存和磁盘资源,它必须在启动时同时申请这三种资源。系统只有在三者都空闲时才会分配,否则该进程需等待,且等待期间不会占用任何资源。

优点:简单直观,从根本上避免“持有部分资源等待其他资源”的情况。
缺点:

  • 资源利用率低:进程可能提前申请暂时不用的资源(如视频编辑进程可能先使用CPU和内存,后期才用磁盘),导致资源长期闲置;
  • 进程延迟启动:若所需资源中有一项长期被占用,进程会被长时间阻塞,无法提前执行部分任务。
(2)策略二:进程申请新资源前必须释放已持有的资源

允许进程动态申请资源,但规定:当进程需要新资源时,必须先释放已持有的所有资源;若要重新使用已释放的资源,需重新申请。

例如,进程A先占用内存资源,当它需要CPU时,必须先释放内存,再同时申请内存和CPU。若CPU可用而内存被占用,进程A会释放内存并进入等待,待内存空闲后再重新获取两者。

优点:相比策略一,资源利用率更高,进程可分阶段使用资源。
缺点:

  • 频繁释放和重新申请资源可能导致进程状态切换开销增大(如反复保存和加载数据);
  • 可能引发“活锁”:两个进程交替释放和申请资源,导致双方都无法稳定持有资源(如A释放内存申请CPU,B释放CPU申请内存,循环往复)。
3. 破坏不可剥夺条件

不可剥夺条件是指资源被进程占用后,不能被强行剥夺。破坏这一条件的核心是允许系统在特定情况下强行剥夺进程已持有的资源,主要适用于可剥夺资源(如CPU、内存)。

(1)实现方式
  • 优先级剥夺:当高优先级进程申请资源时,若资源被低优先级进程占用,系统可强行剥夺低优先级进程的资源,分配给高优先级进程。低优先级进程则需等待资源重新可用。
  • 超时剥夺:规定进程占用资源的最长时间,若超时未释放,系统可强行剥夺资源。

例如,操作系统的CPU调度采用“可剥夺调度”:高优先级进程可以抢占低优先级进程的CPU资源,这本质上就是破坏了CPU资源的不可剥夺条件,避免因CPU竞争导致的死锁。

(2)局限性
  • 仅适用于可恢复的资源(如CPU、内存):这些资源被剥夺后,进程只需重新获取即可继续执行;
  • 对不可恢复资源(如打印机、文件)不适用:强行剥夺可能导致数据不一致(如打印到一半的文件被中断,再次打印会出现重复内容)。
4. 破坏循环等待条件

循环等待条件是指进程间形成资源等待的闭环。破坏这一条件的关键是规定资源申请的顺序,避免闭环的形成,最常用的方法是“资源有序分配法”。

(1)实现方式:资源编号与有序申请
  • 步骤1:资源编号:系统为所有资源类型分配唯一的整数编号(如CPU=1,内存=2,打印机=3,磁盘=4等);
  • 步骤2:有序申请:规定进程必须按“资源编号递增”的顺序申请资源。即进程在申请编号为i的资源后,只能申请编号大于i的资源,不能回头申请编号更小的资源。

例如,进程需要使用打印机(编号3)和内存(编号2)时,必须先申请内存(编号2),再申请打印机(编号3),而不能先申请打印机再申请内存。

(2)为何能破坏循环等待?

假设所有进程都按编号递增顺序申请资源,反证法可证明不会形成循环等待链:
假设存在循环等待链P₁→P₂→…→Pₙ→P₁,其中P₁等待P₂的资源Rₐ,P₂等待P₃的资源Rᵦ,…,Pₙ等待P₁的资源Rᵧ。根据有序申请规则,P₁持有的资源编号 < Rₐ,P₂持有的资源编号 < Rᵦ,…,Pₙ持有的资源编号 < Rᵧ。又因P₁等待的Rₐ由P₂持有,故P₂持有的资源编号 ≥ Rₐ(否则P₂无法申请Rₐ),同理可得Rₐ ≤ Rᵦ ≤ … ≤ Rᵧ ≤ P₁持有的资源编号。这与“P₁持有的资源编号 < Rₐ”矛盾,因此循环等待链不可能存在。

(3)优缺点

优点:资源利用率高,进程可动态申请资源,只需遵守顺序规则。
缺点:

  • 编号固定缺乏灵活性:新增资源时需重新编号,可能影响已有进程;
  • 进程需提前知道所需资源的编号,对动态需求的进程不够友好。
本节小结

死锁预防通过破坏死锁的四个必要条件来避免死锁,具体策略包括:

  • 破坏互斥条件(如SPOOLing技术),但适用范围有限;
  • 破坏持有并等待条件(一次性申请所有资源或先释放再申请),可能降低资源利用率;
  • 破坏不可剥夺条件(优先级剥夺或超时剥夺),仅适用于可恢复资源;
  • 破坏循环等待条件(资源有序分配法),是实际系统中最常用的策略。

死锁预防的优势是无需动态判断系统状态,实现简单;缺点是可能牺牲系统性能或灵活性,适用于对安全性要求高、资源类型相对固定的场景(如嵌入式系统)。

更多推荐