死锁
死锁可以被定义为一组竞争系统资源或相互通信的进程间相互的“永久”阻塞。当一组进程中的所有进程都在等待一个事件(等待请求资源的释放),而只有在进程集合中的其他阻塞的进程才可以触发该事件,这时就成一组进程死锁。
因为没有事件可以触发,故死锁是永久性的。
- 一般情况下,如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此 就永远处于挂起等待状态了,这叫做死锁(Deadlock)。
- 另一种典型的死锁情形是这样:线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放 锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都 永远处于挂起状态了。
不难想象,如果涉及到更多的线程和更多的锁,有没有可能死锁的问题将会 变得复杂和难以判断。
发生死锁的必要条件
1、互斥。一次只有一个进程可以使用资源,其它进程不能访问已分配给其他进程的资源。
2、占用且等待。当一个进程在等待分配得到其它资源时,其继续占有已分配得到的资源。
3、非抢占。不能强行抢占进程中已占用的资源。
4、循环等待。存在一个封闭的进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源。
前三个条件是死锁产生的必要条件但不是充分条件。第四个条件实际上是前三个条件的潜在结果,即假设前三个条件存在,可能发生的一系列事件会导致不可解的循环等待。这个不可解的循环等待实际上就是死锁的定义。条件4中列出的循环等待之所以是不可解的,是因为有前三个条件的存在。
如何预防死锁
一种是间接的预防死锁,即防止前三个必要条件中任意一个的发生;另一种是直接预防死锁,即防止循环等待的发生。
互斥条件不能禁止。
为防止占有且等待的条件,可以要求进程一次性地请求所有需要的资源,并且阻塞这个进程直到所有的请求都同时满足。这个方法比较低效,而且如果分配给一个进程资源,但由于不足全部资源,所以分配给这个进程的资源可能在相当长的一段时间内都处于不可用状态,且在此期间,它们不能被其他进程使用。另一方面进程可能无法预知它需要的所有资源。
预防非抢占条件。如果占有某些资源的一个进程进一步资源请求被拒绝,则该进程必须释放它最初占用的资源,如果有必要,可再次请求这些资源和另外的资源。或者,如果一个进程请求被另一个进程占用的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。
循环等待条件可以通过定义资源类型的线形顺序来预防。如果一个进程已经分配到R类型的资源,那么他接下来请求的资源只能是那些排在R类型之后的资源类型。
这些都可能导致低效的资源使用和低效的进程执行。
如何规避死锁
规避死锁与预防死锁相比,它允许三个必要条件,但通过明智的选择,确保永远不会抵达死锁点,因此,死锁避免比死锁预防允许更多的并发。
如果一个进程的请求会导致死锁,则不会启动此进程。
如果一个进程增加资源的请求会导致死锁,则不允许此分配。
产生死锁的原因
- 因为系统资源不足。
- 进程的推进的顺序不当。
- 资源分配不当。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
待续 ...