死锁产生的原因、条件及死锁的避免和预防

死锁:一组进程中,每个进程都无限等待被该组的另一个进程所占有的资源,因而永远无法得到资源的现象被称为进程死锁,这组进程被称为死锁进程。
可形象将死锁状态描述为:
A和B两个人都没有礼貌,都不愿给彼此让路,所以A和B都在等对方让路,导致谁也过不去。
同样的,也可形象的将活锁状态描述为:
A和B两个人都很有礼貌,A往左边走给B让路,B也往左边走给A让路;或者A往右边走给B让路,B也往右边走给A让路。这种情况也会导致谁也过不去。
死锁产生的原因:
1、竞争资源,系统提供的资源数量有限,不能满足每个进程的需求。
2、多道程序运行时,进程推进顺序不合理。
死锁产生的条件:
1、互斥条件:一个资源每次只能被一个进程使用。
2、请求与保持条件:一个进程因请求资源阻塞时,对已拥有的资源保持不放。
3、不剥夺条件:进程已获得的资源在未使用完之前不能强行剥夺。
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
死锁的避免:
死锁避免是在系统运行过程中注意避免死锁最终的发生。
死锁产生的前三个条件是死锁产生的必要条件,也就是说要产生死锁必须具备的条件,而不是存在这3个条件就一定产生死锁,那么只要在逻辑上回避了第四个条件就可以避免死锁。
死锁避免的基本思想:系统对进程发出的每一个系统能满足的资源申请进行动态检查,并根据检查结果决定是否分配资源;如果分配后系统有可能发生死锁,则不予分配;否则予以分配。
常用的避免死锁的方法:
1、有序分配资源
2、银行家算法,基本思想:在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。
死锁的预防:
1、破坏“不可剥夺”条件:当一个进程占有一个资源后又申请一个资源而无法满足时,则退出原占有的资源。
该策略实现起来复杂且代价大。因为一个资源在使用一段时间后被强行剥夺,会造成前阶段工作失效。
2、破坏“请求和保持”条件:采用静态的一次性资源分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。
3、破坏“互斥”条件:该策略是几乎不可能的,因为资源的互斥性是由其自身的性质决定的。
4、破坏“循环等待”条件:将系统中所有资源顺序编号,一般原则是,较为稀缺、稀少的资源的编号较大。进程申请资源时,必须严格按照资源编号的顺序进行,否则系统不予分配。即一个进程只有得到编号较小的资源时,才能申请编号较大的资源;释放资源时,应按编号递减的次序进行。
解决死锁的方法:
目前有两种方法,一是不让死锁发生;二是可以允许死锁发生,发生后再加以解决。具体有以下4种方法:
1、预防死锁。通过设置某些严格限制破坏死锁产生的条件防止死锁发生,但该方法会导致系统资源利用率过低。
2、避免死锁。在资源动态分配过程中,采用某种方法防止系统进入不安全状态,避免发生死锁。该方法以较弱的限制条件为代价,可获得较高的资源利用。
3、检测死锁。允许系统运行过程中产生死锁,通过在系统中设置检测机构,及时检测出死锁是否真的发生,并能精确的确定与死锁有关的进程与资源,然后采取措施解除死锁。
4、解除死锁。这是与检测死锁相配套的措施,用于将进程从死锁状态下解脱出来。

### 死锁产生条件 死锁是指两个或多个进程在执行过程中因争夺资源而相互等待对方释放已占有的资源,从而导致这些进程都陷入无限期等待的状态。死锁发生的四个必要条件如下: 1. **互斥条件** 资源在同一时刻只能被一个进程占用,其他试图访问该资源的进程必须等待直到当前占有者释放资源[^2]。 2. **请求与保持条件** 进程已经持有了某些资源的同时又申请新的资源,如果新资源无法立即获得,则持有原有资源的进程进入阻塞状态[^1]。 3. **可剥夺条件** 已经分配给某进程的资源,在未使用完毕之前能强制收回,只有拥有该资源的进程才能主动释放资源[^2]。 4. **循环等待条件** 存在一个由若干进程组成的环形链表,其中每个进程都在等待下一个进程中所持有的某种资源[^3]。 --- ### 预防死锁的方法 为了防止死锁的发生,可以从破坏上述四个必要条件之一入手。以下是几种常见的预防措施: #### 1. 破坏互斥条件 通过减少独占性资源的数量或者改变资源共享方式来降低冲突的可能性。例如,对于共享数据结构可以考虑使用无编程技术或其他并发控制手段替代传统的定机制[^1]。 #### 2. 破坏请求与保持条件 要求进程一次性申请所需的全部资源后再开始运行;如果没有足够的可用资源满足需求,则让进程暂时挂起直至有足够的资源为止。这种方法虽然简单有效,但可能导致资源利用率下降并增加饥饿风险[^2]。 #### 3. 破坏可剥夺条件 当某个正在使用的资源变得再需要时,应该及时将其归还到池子里面去供别的线程调用。另外也可以设计成允许强行回收那些长时间未能完成工作的任务所占据的关键性资产。 #### 4. 破坏循环等待条件 按照一定的次序为所有的资源编号,并规定任何进程在获取多种类型的资源时都要遵循从小号到大号的原则依次索取。这样就可以避免形成闭环依赖关系。 此外还可以借助于高级同步原语比如信号量集、管程等工具实现更精细粒度上的协调管理,进而规避潜在隐患[^4]。 ```cpp // 示例代码展示如何通过加顺序避免死锁 #include <iostream> #include <thread> #include <mutex> std::mutex m1, m2; void thread_func_1() { std::lock_guard<std::mutex> lock_m1(m1); // 定m1 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟延迟操作 std::lock_guard<std::mutex> lock_m2(m2); // 定m2 std::cout << "Thread 1 acquired both locks." << std::endl; } void thread_func_2() { std::lock_guard<std::mutex> lock_m1(m1); // 定m1 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟延迟操作 std::lock_guard<std::mutex> lock_m2(m2); // 定m2 std::cout << "Thread 2 acquired both locks." << std::endl; } int main() { std::thread t1(thread_func_1); std::thread t2(thread_func_2); t1.join(); t2.join(); return 0; } ``` 以上程序展示了如果注意加顺序可能会引发死锁的情况。为了避免这种情况发生,可以在实际应用中统一所有线程对同一组对象进行加时采用固定的先后顺序。 --- ### 总结 综上所述,理解死锁产生原因及其背后逻辑至关重要。针对同场景可以选择合适的技术路线加以防范,既保障系统的稳定性又能兼顾效率最大化目标达成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值