多线程编程---线程死锁

来源:互联网 发布:数据修炼系统顶点 编辑:程序博客网 时间:2024/06/05 16:51

什么是死锁?

是指多个线程在运行过程中因争夺资源而造成的一种僵局(DeadlyEmbreace)即互相等待的现象,当线程处于这种僵持状态时,若无外力作用,它们都将无法向前推进。

举个栗子:如果同一个线程先后两次调用lock,在第一次调用时,由于锁已经被占,该线程会挂起等待别的线程释放锁,然而锁正是被自己占着的,该线程又被挂起,没有机会释放锁,因此,就永远处于挂起等待状态了,这叫做死锁(Deadlock)。

另种典型的死锁情形是这样 : 线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。


死锁产生的原因

(1).竞争资源。当系统中供多个线程共享的资源如打印机,公用队列等,其数目不足以满足诸线程的需要的时候,会引起诸线程对资源的竞争而产生死锁。

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

产生死锁的4个必要条件

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

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

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

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

如何避免死锁

(1)在编写多线程程序之前,首先编写正确的程序,然后再移植到多线程。
(2)时刻检查自己写的程序有没有在跳出时忘记释放锁。
(3)如果自己的模块可能重复使用一个锁,建议使用嵌套锁。
(4)对于某些锁代码,建议使用库里面的锁,或者自己曾经编写的锁。
(5)如果某项业务需要获取多个锁,必须保证锁的按某种顺序获取,否则必定死锁。
(6)编写简单的测试用例,验证有没有死锁。
(7)编写验证死锁的程序,从源头避免死锁。

避免死锁的常见算法

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

  (1).可利用资源向量Available  (2).最大需求矩阵Max  (3).分配矩阵Allocation  (4).需求矩阵Need

2).银行家算法

Request请求向量,

 (1).如果Request[i] <= Need[i][j]转下步,否则它所需要的资源数已超过它所需要的最大值 (2).如果Request[i] <= Available[i][j]转下步,否则尚无足够资源,进程需等待   (3).系统试分配给进程p,并修改Available,Allocation和Need               Available[j] -= Request[j]               Allocation[i][j] += Request[j]               Need[i][j] -= Request[j] (4)系统执行安全性算法,检查此次资源分配后系统是否处于安全状态.若安全,才正式分配;否则恢复原来的分配状态,让该进程等待

3).安全性算法

(1).设置两个向量,工作向量Work,在执行安全性算法开始时 Work=Available;Finish:表示有足够的资源分配给进程,使之运行完成,Finish[i]=false;当有足够资源分配给进程时,再另Finish[i]=false

(2).从进程集合中找到一个满足该条件的进程:

       Finish[i]=false       Need[i][j] <= Work[j]

(3).当进程获得资源后,可顺利执行,并修改Work向量和Finsh向量

      Work[i] += Allocation[i][j]      Finish[i]=true

(4).如果所有进程的Finish[i]=true说明系统处于安全状态,否则系统处于不安全状态.

原创粉丝点击