一.死锁的定义

    所谓死锁,是指多个线程在运行过程中因争夺资源而造成的一种僵局,当线程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。

二.产生死锁的原因

    产生死锁的原因可总结为以下两点:

    (1)竞争资源。当供线程共享的资源数目不足以满足诸线程的需要时,会引起诸线程对资源的竞争而产生死锁。

    (2)线程间推进顺序非法。线程在运行过程中,请求和释放资源的顺序不当,也会导致线程死锁。

    下面详细分析产生死锁的原因:

1.竞争资源引起线程死锁

    a.可剥夺和非剥夺性资源

        可把系统的资源分为两类,一类是可剥夺性资源,是指某线程在获得这类资源后,该资源可以在被其他线程或系统剥夺。另一类资源是不可剥夺性资源,当系统把这类资源分配给线程后,再不能强行收回,只能在线程用完后自行释放。

    b.竞争非剥夺性资源

        在系统中所配置的非剥夺性资源,由于他们的数量不能满足诸线程运行的需要,会使线程在运行过程中,因争夺这些资源而陷入僵局。

    c.竞争临时性资源

        所谓临时性资源,指由一个线程产生,被另一个线程使用一短暂时间后便无用的资源,也称之为消耗性资源,它也可能引起死锁。

三.产生死锁的必要条件

    死锁的发生必须具备下列四个必要条件:

    (1)互斥条件:指线程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个线程占用。如果此时还有其他线程请求该资源,则请求者只能等待,直至占有该资源的线程用完释放。

    (2)请求和保持条件:指线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又已被其他线程占有,此时请求线程阻塞,但又对自己已获得的其他资源保持不放。

    (3)不剥夺条件:指线程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

    (4)环路等待条件:指在发生死锁时,必然存在一个线程——资源的环形链,即线程集合{P0,P1,P2,P3,...Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,......,Pn正在等待P0占用的资源。

四.处理死锁的基本方法

    (1)预防死锁。该方法是通过设置某些限制条件,去破坏产生死锁的四个必要条件质疑你或者更多的条件,来预防发生死锁。

    (2)避免死锁。在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免发生死锁。

    (3)检测死锁。通过系统所设置的检测机构,及时的检测出死锁的发生,并精确地确定与死锁有关的进程和资源;然后采取适当措施从系统中将已发生的死锁清除掉。

    (4)解除死锁。当检测到系统中已发生死锁时,须将线程从死锁中解脱出来。常用的实施方法是撤消或挂起一些线程,以便回收一些资源,再将资源分配给已处于阻塞状态的线程,使之转换为就绪状态,以继续运行。

五.系统安全状态

    安全状态:指系统能按某种线程顺序(P1,P2,P3,...Pn),来为每个线程分配其所需资源,直至满足每个线程对资源的最大需求,使每个线程都可以顺利的完成。如果系统无法找到这样一个安全序列,则该系统处于不安全状态。

    并非所有的不安全状态都必然会转换为死锁状态,但当系统进入不安全状态后,就有可能进入死锁状态。反之,只有系统处于安全状态,系统便可以避免进入死锁状态。

六.利用银行家算法避免死锁

    (1)银行家算法中的数据结构

        a.可利用资源向量Available。这是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态的改变。

        b.最大需求矩阵Max。这是一个n*m的矩阵,它定义了系统中n各进程中的每一个线程对m类资源的最大需求。

        c.分配矩阵Allocation。这是一个n*m的矩阵,它定义了系统中每一类资源当前已分配给每一个进程的资源数。

        d.需求矩阵Need。这也是一个n*m的矩阵,用来表示每一个进程尚需的各类资源数。

    (2)银行家算法

        设Request[j]是进程P的请求向量,如果Request[j]=K,表示进程P需要K个Rj类型的资源,当P发出资源请求后,系统按下属步骤进行检查:

        a.如果Request[j]<=Need[i,j],转向步骤b;否则认为出错,因为它所需的资源数已超过它所宣布的最大值。

        b.如果Request[j]<=Available[j],转向步骤c;否则,表示尚无足够资源,P须等待。

        c.系统试探着把资源分配给进程P,并修改数据结构的数值.

        d.系统执行安全性算法。检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程P,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程P等待。