操作系统-死锁
并发性:死锁和饥饿
死锁
基本概念
死锁:一组相互竞争系统资源或进行通信的进程间“永久”阻塞的情况。当一组进程中的每个进程都在等待某个事件,而只有在这组进程中的其他被阻塞的进程才可以触发该事件,这组进程就发生死锁。因为没有事件能够被触发,因此死锁是永久性的。
活锁:指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试—失败—尝试—失败的过程。处于活锁的实体是在不断的改变状态,活锁有可能自行解开。(类似于不断谦让的过程)
可重用资源:一次只能供一个进程安全地使用,并且不会由于使用而耗尽的资源。如处理器/ io通道、内存外存、设备以及文件、数据库和信号量等。
可消耗资源:可以被创建(生产)和销毁(消耗)的资源。这种资源的数目没有显示,一个无阻塞的生产进程可以创建任意数目的这类资源。当一个消费进程得到一个资源的时候,该资源就不再存在了。比如有中断、信号、消息和I/O缓冲区中的信息。
资源分配图:刻画进程的资源分配的有向图。参考
死锁的条件
死锁产生的主要原因包括系统资源的竞争以及进程推进顺序非法。
死锁产生有三个必要条件:
1.互斥:一次只有一个进程可以使用一个资源。其他进程不能访问已分配给其他进程的资源
- 占有且等待:当一个进程等待其他进程的时候,继续占有已分配的资源
- 不可抢占:不可强行抢占进程已占有的资源
满足前三个条件,可能发生的一系列事件会导致不可解的循环等待。这个不可解的循环等待实际上才是死锁的定义,因此还有一个充分条件:
- 循环等待:存在一个封闭的进程链,使得每个进程至少占有此链中下一个进程所需要的一个资源。
死锁的处理策略
原则 |
资源分配策略 |
方案 |
优点 |
缺点 |
预防 |
保守的,宁可资源闲置 |
一次性请求所有资源 |
对执行一连串活动的进程非常有效;不需要抢占 |
低效、延迟进程的初始化 必须知道将来的资源请求 |
抢占 |
用于状态保存和恢复的资源很方便 |
过于经常地没必要的抢占 |
||
资源排序 |
通过编译时检测可以实施 不需要在运行时候计算 |
不便灵活申请新资源 |
||
避免 |
运行时判断 |
操作以发现至少一条安全路径 |
不需要抢占 |
必须知道将来的资源请求 进程不能被长时间阻塞 |
检测 |
非常自由,只要允许就分配 |
周期性地调用以测试死锁 |
不会延迟进程的初始化 易于在线处理 |
通过抢占解除死锁,造成损失 |
死锁的预防
防止死锁的发生只需要破坏死锁产生的四个条件之一即可。
1.破坏互斥条件
允许系统的资源都能共享使用,但是有些资源根本不能同时访问,如打印机等。因此,破坏互斥不太可行
2.破坏占有且等待
要求进程一次性地请求所有需要的资源,并且阻塞这个进程直到所有的请求都满足。但是这个方法是低效率的,一方面进程可能被长时间阻塞。另一方面,分配给一个进程的资源可能长时间不会使用到,但是在此期间,也不能被其他进程使用。
3.破坏不可抢占
如果占有某些资源的进程进一步申请资源被拒绝的时候,该进程必须释放它最初占有的资源。
一个进程请求当前被另一个进程占有的一个资源,操作系统可以抢占另一个进程,要求它释放资源,要求优先级不同。
4.破坏循环等待
定义资源类型的线性顺序,如果一个进程分配到了R型,则接下来的资源只能是排在R型之后的资源类型。
死锁的避免
死锁的避免同样也是属于事先预防的策略,但并不是事先采取某种限制措施破坏死锁的必要条件,而是在资源动态分配过程中,防止系统进入不安全状态,以避免发生死锁。死锁避免允许三个必要条件,限制条件更弱,能够获得更好的系统性能和允许更多的并发。
死锁避免不需要死锁预防中的抢占和回滚进程,限制也少。但是,死锁避免的限制在于:必须事先声明每个进程请求的最大资源,所讨论的进程是无关的,没有同步要求的限制,分配的资源数目必须是固定的,在占有资源的时候,进程不能退出。
1.进程启动拒绝
如果一个进程的请求会导致死锁,则不启动此进程。
在分配资源给进程之前需要考虑是否会导致系统进入不安全状态。
安全状态指的是系统能按某种进程推进顺序,为每个进程分配所需资源,直到满足每个进程对资源的最大需求,使得每个进程都可顺序地完成。如果不存在这样的序列,则系统就是不安全的。系统进入不安全状态,就有可能进入死锁状态,反之,只要系统处于安全状态,系统便可避免进入死锁状态。
2.资源分配拒绝
资源分配拒绝策略又称之银行家算法。进程向操作系统请求分配资源,操作系统按照规则为进程分配资源。当进程首次申请资源的时候,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求则进行分配,否则就推迟分配。当进程在执行中继续申请资源的时候,先测试该进程已占用的资源与本次申请的资源数之和是否超过了它自身的最大需求量,如果超过则拒绝,如果没有超过再测试系统现存的资源能否满足进程的需要。若能则分配,否则延迟分配。
数据结构描述:
struct state{
int resource[m]; //表示资源数目
int available[m]; //未分配给进程的每种资源的总量
int claim[n][m]; //进程对资源的最大需求 有时也用max表示
int allocation[n][m] //n是进程数,m是资源种类数目
}
银行家算法描述:
安全性算法
举例说明
死锁的检测
系统在分配资源的时候不采取任何措施,而是周期性地执行一个算法(前面的安全性算法)检测死锁条件4-循环等待条件。
死锁定理-资源分配图
1.在资源分配途中,找出既不阻塞又不是孤点的进程Pi,消去它所有的请求边和分配边,使之成为孤立的结点。
2.进程Pi所释放的资源,可以唤醒某些阻塞进程。原来的阻塞进程可能变成非阻塞进程。重复1)
如果消去了所有的边,则该图可以简化并且不存在死锁,否则就存在。
死锁解除
- 取消所有的死锁进程
- 把每个死锁进程回滚到之前的检查点,并且重新启动所有进程。
- 连续取消死锁进程直到不再存在死锁。
- 连续抢占资源直到不再存在死锁。被抢占的进程需要回滚。