Linux--线程死锁

一、死锁

1.什么是死锁?

死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者彼此通信而造成的一种阻塞现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或者系统产生了死锁,这些永远在等待的进程(线程)称为死锁进程(线程)。

举一个简单的例子:有A和B两个进程,都需要1和2两种资源,但是目前的状态就是:A进程持有1等待2,B进程持有2等待1,两个进程都在等另一份资源的同时都不愿意释放自己所拥有的资源,这就导致了死锁现象的产生。

进程是这个样子产生的死锁,线程也是同样的。

2.死锁的情况

(1)线程自己将自己锁住 
一般情况下,如果同一个线程先后两次调用lock,在第二次调⽤用时,由于锁已经被占用,该线程会挂起等待占用锁的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此 就永远处于挂起等待状态了,于是就形成了死锁(Deadlock)。 
(2)多线程抢占锁资源被困 (同上面进程的例子)

加入线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放 锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都 永远处于挂起状态了,死锁再次形成。

如下图:


二、产生死锁的四个必要条件

(1)互斥条件:进程(线程)所申请的资源在一个时间段内中只能被一个进程(线程)所占用;

(2)请求和保持条件:进程(线程)已经至少占用一种资源,且自己占用的资源保持不变,但又提出了新的资源请求,而该资源被其他进程(线程)所占用;

(3)不可抢占条件(不可剥夺条件):进程(线程)已经获得的资源在未使用完之前,不可抢占;

(4)循环等待条件(环路等待条件):在发生思索时,必然发生一个进程(线程)资源的循环链。

三、处理死锁

1.处理死锁的思路

(1)预防死锁:破坏产生死锁条件中的一个或者多个(注意,互斥条件不能被破坏,否则会造成结果的不可再现性);

(2)避免死锁:在资源匹配过程中,防止系统进入不安全区;

(3)检测死锁:通过检测机构检测死锁的发生,如果发生死锁,则采用相应的措施解除死锁;

(4)解除死锁:发生死锁后,解脱进程(线程),通常是撤销进程(线程),回收资源,再分配给正处于阻塞状态的进程(线程)。

2.预防死锁的方法

(1)破坏请求和保持条件

1>协议1

所有进程(线程)开始前,必须一次性的申请所需的所有资源,这样运行期间不会再提出资源要求,破坏了请求条件,即使有一种资源不能满足需求,也不会给它分配空闲的字眼,这样子它就没有了资源,破坏了保持条件,从而预防死锁的发生。

2>协议2

允许一个进程(线程)只获得初期的资源就开始运行,然后再把运行完的资源释放出来,然后再请求新的资源

(2)破坏不可抢条件

当一个已经保持了某种不可抢占资源的进程(线程),提出新资源请求不能被满足时,它必须释放已经保持的所有资源,以后徐亚时再重新申请

(3)破坏循环等待条件

对系统中的所有资源类型进行线性排序,然后规定每个进程(线程)必须按序列号递增的顺序请求资源。假如进程(线程)请求到了一些序列号较高的资源,然后有请求一个序列较低的资源使能,必须先释放相同或者更高序列号的资源才能申请低序列号的资源。(多个同类资源必须请求)

3.解决死锁问题的算法

(1)银行家算法原理

1>可利用资源向量Available[m]。m为系统中的资源种类数,如果向量Available[j] = K,则表示系统中Rj类资源由K个。 
2>最大需求矩阵Max[n][m]。m为系统中的资源种类数,n为系统中正在运行的进程(线程)数,如果Max[i][j] = K,则表示进程i需要Rj类资源的最大数目为K个。 
3>分配矩阵Allocation[n][m]。m为系统中的资源种类数,n为系统中正在运行的进程(线程)数,如果Allocation[i][j] = K,则表示进程i当前已分得Rj类资源的数目为K个。 
4>需求矩阵Need[n][m]。m为系统中的资源种类数,n为系统中正在运行的进程(线程)数,如果Need[i][j] = K,则表示进程i还需要Rj类资源K个。 
以上三个矩阵间的关系: 

Need[i][j] = Max[i][j] - Allocation[i][j]

具体算法:

设Request( i)是进程Pi的请求向量,如果Request(i) [j] = K,表示进程Pi需要K个Rj类型的资源。 
1>如果Request(i) [j] <= Need[i][j],转向步骤2>。 
2>如果Request(i) [j] <= Available[j] ,转向步骤3>。 
3>系统尝试着把资源分给进程Pi。 
     Available[j] = Available[j] - Request(i) [j]; 
     Allocation[i][j] = Allocation[i][j] + Request(i) [j]; 
     Need[i][j] = Need[i][j] - Request(i) [j]; 

4>系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。

(2)安全性算法 
1>设置两个向量: 
1》工作向量Work[m],它表示系统可提供给进程继续运行所需要的各类资源数目,初始值Work = Available。 
2》Finish:它表示系统是否有足够的资源分配给进程,使其运行完成。开始时Finish[i] = false,当有足够的资源分配给进程时Finish[i] = true。 
2>从进程(线程)集合中找到一个能满足下述条件的进程(线程)。 
1》Finish[i] = false 
2》Need[i][j] <= Work[j],如果找到转到步骤3》,没找到转到步骤4》。 
3》Work[j] = Work[j] + Allocation[i][j] ; 
Finish[i] = true; 
go to step 2; 
4》如果所有进程(线程)的Finish[i] = true都满足,表示系统处于安全状态,反之系统处于不安全状态。





猜你喜欢

转载自blog.csdn.net/cherrydreamsover/article/details/80149686