操作系统面试高频(死锁)
死锁
1 死锁概述⭐⭐⭐⭐
死锁概述
定义
死锁(Deadlock)是指多个进程或线程因争夺系统资源(如锁、文件、网络连接等)或通信顺序不当,导致所有进程 / 线程均无法继续执行的现象。若无外部干预,死锁会导致程序挂起或系统资源永久占用。
死锁的四大必要条件(Coffman 条件)
- 互斥条件 资源同一时间只能被一个进程 / 线程占用。 例如:文件被进程 A 打开后,其他进程无法同时写入。
- 持有并等 待进程 / 线程持有至少一个资源,并等待获取其他进程持有的资源。 例如:进程 A 持有锁 1,同时请求锁 2。
- 不可抢占 资源只能由持有者主动释放,其他进程无法强行抢占。 例如:锁必须由持有线程主动解锁。
- 循环等待 多个进程 / 线程形成环形等待链,每个进程等待下一个进程持有的资源。 例如:进程 A → 进程 B → 进程 C → ... → 进程 A,形成循环依赖。
死锁的影响
- 资源浪费:进程 / 线程永久占用资源却无法推进。
- 系统性能下降:死锁可能导致应用无响应或服务中断。
- 数据不一致:若死锁发生在事务处理中,可能破坏数据完整性。
死锁的常见场景
- 资源竞争 多个线程争夺共享资源(如锁、文件)且未合理释放。
- 嵌套锁顺序不一致 不同线程以不同顺序获取多个锁。
- 生产者 - 消费者模型缺陷 缓冲区满时生产者等待,缓冲区空时消费者等待,且未设置超时机制。
死锁的处理策略
预防(Deadlock Prevention)
破坏四大必要条件中的一个或多个:
- 互斥条件:使用可抢占资源(如虚拟内存)。
- 持有并等待:要求进程一次性申请所有资源(资源预分配)。
- 不可抢占:允许强行抢占资源(如终止持有资源的进程)。
- 循环等待:按固定顺序申请资源(如锁编号递增)。
避免(Deadlock Avoidance)
在资源分配前动态检查是否会导致死锁:
- 银行家算法:通过模拟资源分配,确保系统始终处于 “安全状态”。
检测与解除(Deadlock Detection & Recovery)
- 检测:定期扫描系统,通过资源分配图判断是否存在循环等待。
- 解除:终止部分进程(如优先级最低的进程)。抢占资源(如强制释放锁)。重启系统(极端情况)。
死锁的预防建议
- 限制锁的数量:减少资源竞争。
- 按顺序加锁:所有线程以相同顺序获取多个锁。
- 设置超时机制:避免无限等待。
- 使用无锁数据结构:如原子操作(
atomic
)、CAS(Compare-and-Swap)。 - 最小化锁的持有时间:尽快释放非必要资源。
总结
死锁是并发编程中难以完全避免的问题,需通过合理的资源管理、锁策略和代码设计降低风险。在分布式系统中,死锁问题更复杂(如网络延迟导致的资源竞争),需结合分布式锁、超时机制等手段处理。
2 死锁的起因⭐⭐⭐⭐⭐
造成死锁的起因主要是由于系统资源的竞争和分配不合理,具体来说,有以下几个方面:
- 竞争互斥资源:多个进程竞争同一个互斥资源(比如一块儿共享内存),这种资源只能被一个进程占用,其他进程需要等待资源释放。
- 进程持有部分资源而请求资源:进程已经获得了部分资源,但是又请求其他进程正持有的资源,而这些资源又无法被抢占。
- 进程推进顺序不当引起死锁,除了系统中多个进程对资源的争夺会引起死锁外,进程在运行的过程中,对资源进行申请和释放的顺序是否合法,也是在系统中产生死锁的一个重要因素。
- 资源分配不当:系统在分配资源时出现问题,比如错误的资源分配顺序或者过多地分配资源,从而导致某些进程一直无法获得需要的资源。
- 循环等待:各个进程之间互相等待对方所持有的资源释放,形成了一个循环等待的状态,从而导致了死锁的出现。
因此,为了避免出现死锁,需要合理地设计程序和系统,合理分配资源,并采取一些解决措施,如资源预分配、进程抢占、超时机制和死锁检测和恢复等。
3 死锁的四个必要条件⭐⭐⭐⭐⭐
死锁是指两个或多个进程在执行过程中,因争夺系统资源而产生的一种僵局,它们都无法继续执行下去。产生死锁的原因在于这些进程相互占用着所需资源却又无法释放,无法向前推进,形成了死结。死锁具有以下四个必要条件:
- 互斥条件:至少有一种资源必须被独占而不能共享,即进程只能拥有一个资源。
- 请求与保持条件:进程必须同时持有所需要的资源并且在等待它未拥有的资源时不释放自己所占有的资源。
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能被其他进程所强制夺去。
- 环路等待条件:由若干个进程之间形成一种头尾相接的循环等待资源的关系,使得请求资源的进程永远不能得到满足。
当以上四个条件全部满足时,就会发生死锁。对于死锁的预防和避免,可以采取一些措施,例如破坏死锁中的其中一个或多个条件等。
4 预防死锁的方法⭐⭐⭐⭐⭐
死锁是多进程或多线程并发执行时出现的一种严重问题,预防死锁可从破坏死锁产生的四个必要条件(互斥条件、占有并等待条件、不可抢占条件、循环等待条件)入手,以下是详细介绍:
破坏互斥条件
互斥条件指进程对所分配到的资源进行排他性使用,即在一段时间内某资源只由一个进程占用。多数情况下,这一条件无法被破坏,因为像打印机、磁带机等某些资源本身的属性决定了它们必须互斥访问。不过,某些资源可通过某种技术手段转化为共享资源,从而破坏互斥条件。
破坏占有并等待条件
占有并等待条件是指进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。可采用以下两种方法来破坏该条件:
- 预先静态分配法:进程在运行前一次性申请它所需要的全部资源,在它的资源未满足前,不把它投入运行。一旦投入运行后,这些资源就一直归它所有,也不再提出其他资源请求,这样就可以保证进程在运行过程中不会再等待资源,从而破坏了占有并等待条件。
- 逐步分配资源并释放已用资源:在进程需要资源时才进行分配,但当进程请求新资源而无法立即满足时,必须释放它已占有的所有资源,待以后需要时再重新申请。
破坏不可抢占条件
不可抢占条件是指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。破坏该条件的方法是,当一个已经保持了某些不可被抢占资源的进程,提出新的资源请求而不能立即得到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请。
破坏循环等待条件
循环等待条件是指在发生死锁时,必然存在一个进程 —— 资源的环形链,即进程集合 {P0,P1,P2,・・・,Pn} 中的 P0 正在等待一个 P1 占用的资源;P1 正在等待 P2 占用的资源,……,Pn 正在等待已被 P0 占用的资源。可以通过以下方式破坏该条件:
- 资源有序分配法:将系统中的所有资源按类型赋予一个编号(如打印机为 1、磁带机为 2 等),规定每个进程必须按编号递增的顺序请求资源,同类资源一次申请完。这样就不会出现循环等待的情况。
5 避免死锁⭐⭐⭐⭐⭐
为避免死锁,可以从以下几个方面着手:
- 破坏循环等待条件:通过定义资源使用规则,避免进程之间形成循环等待的情况。
- 预防死锁:避免使用可能导致死锁的资源,尽量减少保持资源的时间,合理分配资源,从而降低死锁的发生概率。
- 死锁检测和恢复:实时监测系统资源的状态,及时发现死锁,以及采取相应的措施,如释放资源、抢占进程等来解除死锁状态。
- 调整资源分配策略:在资源分配策略方面可以尝试采取其他方案,如资源复制、动态资源分配等,进一步减少死锁的概率。
总之,避免死锁需要综合考虑资源分配、进程调度、死锁检测等多方面的因素,并采取相应的措施来确保系统的可靠性和稳定性。具体而言,尽可能地破坏循环等待条件、避免死锁产生、实时检测死锁状态、调整资源分配策略等都是可行的方法。
6 死锁的检测和解除⭐⭐⭐⭐⭐
死锁的检测和解除死锁的检测和解除是一种重要的死锁处理方法。它的基本思想是通过检测系统的状态并采取相应的措施来解除死锁状态。
在实际应用中,可以采用以下方法来检测和解除死锁:
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
该专栏面向嵌入式开发工程师、C++开发工程师,包括C语言、C++,操作系统,ARM架构、RTOS、Linux基础、Linux驱动、Linux系统移植、计算机网络、数据结构与算法、数电基础、模电基础、5篇面试题目、HR面试常见问题汇总和嵌入式面试简历模板等文章。超全的嵌入式软件工程师面试题目和高频知识点总结! 另外,专栏分为两个部分,大家可以各取所好,为了有更好的阅读体验,后面会持续更新!!!