计算机系统中的死锁:
死锁的起因,通常源于多个进程对资源的争夺, 不仅对不可抢占资源进行争夺时会引起死锁,而且对可消耗资源进行争夺时,也会引起死锁。
可抢占资源:
可把系统中的资源分成两类,一类是可抢占性资源,是指某进程在获得资源后,资源可以被其他进程或或系统抢占。例如优先级高的高的资源可以抢占优先级低的进程处理机。又可以把一个进程从一个存储区转移到另一个存储区,在内存紧张时,还可将一个进程从内存调出到外存上,即抢占该进程的内存空间,即cpu和主存均属于可抢占性资源,对于这类资源是不会引起死锁的。
不可抢占资源:
另一类资源是不可抢占资源,即一旦系统把某资源分配给进程后,就不能将它强行收回,只能在进程用完后自行释放,例如,当一个进程已开始刻录光盘时,如果突然将刻录机分配给另一个进程,其结果必然将损坏正在刻录的光盘,因此只能等刻好光盘以后由进程自己释放刻录机,另外磁带机,打印机等也属于不可抢占资源。
1.竞争不可抢占资源引起的死锁:
通常系统中所有的不可抢占资源其数量不足以满足多个进程运行的需要,是的进程在运行过程中,会因争夺资源陷入僵局,例如,系统中有两个进程p1,p2,他们都准备写两个文件f1,f2,这两者都属于可重用和不可抢占资源,进程p1打开f1,然后再打开文件f,后打开f1,。
两个进程在并发执行时,如果p1先打开f1和f2,然后p2再打开f1(或f2),由于文件f1或f2,由于f1(f2)已被p1打开,故p2处于会被阻塞,当p1写完文件f1(或f2)而关闭f1(或f2时,p2就会由阻塞状态转为就绪状态,被调度执行后重新打开文件f1(或f2),在这种情况下,p1和p2都能正常运行下去,。
但如果p1打开文件f1的同时,p2去打开f2,每个进程都占有一个打开的文件, 此时就可能出现问题,。因为p1试图打开f2,p2试图打开f1时,这两个进程就会因都会因文件被打开而被阻塞,他们希望对方关闭自己所需要的文件,但谁也无法运行,因此两个进程将会无限地等待下去,而形成死锁。
2.竞争可消耗资源引起的死锁
在利用消息通信机制进行通信时引起的死锁情况,若m1,m2,m3是可消耗性资源,
P1:..send(p2,m1); receive(p3,m3);..
P2:..send(p3,m2); receive(p1,m1);..
P3:..send(p1,m3); receive(p2,m2);..
这三个进程都可将消息发送给下一个进程,相印地,他们也能够接受从上一个进程发送来的消息,因此三个进程可以顺利地运行下去,而不会发生死锁,但若先执行receive操作,然后执行send操作,即按下述运行顺序
p1:receive(p3,m3);..P1:..send(p2,m1)
p2:receive(p1,m1);..P2:..send(p3,m2);
p3:receive(p2,m2);....send(p1,m3);
则这三个进程将永久地阻塞他们的receive操作,等待一条永远不会发出的消息,于是发生 了死锁。
产生死锁的必要条件:
(1)互斥条件。进程对所分配到的资源进行排他性使用,即在一段时间内,某资源只能被一个进程占用,如果此时还有其他进程请求该资源,则请求进程只能等待,直至占用该资源的进程用必释放。
(2)请求和保持条件。进程保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己获得的资源保持不放。
(3)不可抢占条件。进程已获得的资源在未使用完之前不能被抢占,只能在进程使用完时自己释放。
(4)循环等待条件。在发生死锁时,必然存在一个进程-资源的循环链,即进程集合{p1,p2,p3...pn}中的p0正在等待一个p1占有的资源,p1正在等待p2占有的资源,...pn正在等待p0占有的资源。
处理死锁的方法
(1)预防死锁
(2)避免死锁
(3)检测死锁
(4)解除死锁
避免死锁的方法(银行家算法)
最具有代表性的避免死锁的算法是dijkstra的银行家算法,起这样的名字是由于该算法原本是为银行系统设计的,以确保在银行发放现金贷款时,不会发生不能满足所有客户需要的情况。
1.银行家算法的数据结构
(1)可利用资源向量Available.代表可利用资源的数目,起初始值是系统中配置该类全部可用资源数目,其数值随随该类资源的分配和回收动态地变化。
(2)最大需求MAX,这是一个n*m的矩阵,如果MAX[i,j]=k,则代表进程i需要Rj类资源最大数目为k.
(3)分配矩阵Allcoation。这也是一个n*m矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数,如果Need[i,j]=k,则表示进程i还需要Rj类资源方可完成任务。
Need[i,j]=MAX[i,j]-Allcoation[i,j]
2.银行家算法
设Request是进程p1的请求向量,如果Request[j]=k,表示进程p需要Rj类型的资源,当p发出资源请求后,系统按下述步骤检查
(1)如果Request[j]<=Need[i,j],便转向步骤2,否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
(2)如果Request[j]<=Available[j],变转向步骤3,否则,表示尚无足够资源,p1需要等待。
(3)系统试探着把资源分配给进程p1,并修改数据结构中的数值。
Available[j]=Available[j]-Request[j]
Allocation[i,j]=Allocation[i,j]+Request[i,j]
Need[i,j]=Need[i,j]-Request[j]
(4)系统执行安全性算法,检查此次资源分配后是否处于安全状态,若安全,正式分配给进程,完成此次分配,否则此次分配失败,恢复原来分配资源状态。