对死锁的探究

什么是死锁

死锁是进程死锁的简称,是由Dijkstra于1965年研究银行家算法时首先提出来的。它是计算机操作系统乃至并发程序设计中最难处理的问题之一。

产生死锁的必要条件

〈1〉互斥条件即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有。这种独占资源如CD-ROM驱动器,打印机等等,必须在占有该资源的进程主动释放它之后,其它进程才能占有该资源。这是由资源本身的属性所决定的。如独木桥就是一种独占资源,两方的人不能同时过桥。

〈2〉不剥夺条件进程所获得的资源在未使用完毕之前,资源申请者不能强行地从资源占有者手中夺取资源,而只能由该资源的占有者进程自行释放。如过独木桥的人不能强迫对方后退,也不能非法地将对方推下桥,必须是桥上的人自己过桥后空出桥面(即主动释放占有资源),对方的人才能过桥。

〈3〉请求与保持条件进程至少已经占有一个资源,但又申请新的资源;由于该资源已被另外进程占有,此时该进程阻塞;但是,它在等待新资源之时,仍继续占用已占有的资源。还以过独木桥为例,甲乙两人在桥上相遇。甲走过一段桥面(即占有了一些资源),还需要走其余的桥面(申请新的资源),但那部分桥面被乙占有(乙走过一段桥面)。甲过不去,前进不能,又不后退;乙也处于同样的状况。

〈4〉循环等待条件存在一个进程等待序列{P1,P2,…,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一源,……,而Pn等待P1所占有的的某一资源,形成一个进程循环等待环。就像前面的过独木桥问题,甲等待乙占有的桥面,而乙又等待甲占有的桥面,从而彼此循环等待。

只要破坏死锁发生时这四个必要条件中的任意一个条件,死锁就不会发生。这就为我们解决死锁问题提供了可能。一般地,解决死锁的方法分为死锁的预防,避免,检测与恢复三种。

死锁的预防

死锁的预防是保证系统不进入死锁状态的一种策略。它的基本思想是要求进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。

〈1〉打破互斥条件即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。

〈2〉打破不可剥夺条件即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。

〈3〉打破请求与保持条件可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。但是,这种策略也有如下缺点: (1)在许多情况下,一个进程在执行之前不可能知道它所需要的全部资源。这是由于进程在执行时是动态的,不可预测的; (2)资源利用率低。无论所分资源何时用到,一个进程只有在占有所需的全部资源后才能执行。即使有些资源最后才被该进程用到一次,但该进程在生存期间却一直占有它们,造成长期占着不用的状况。这显然是一种极大的资源浪费; (3)降低了进程的并发性。因为资源有限,又加上存在浪费,能分配到所需全部资源的进程个数就必然少了。

〈4〉打破循环等待条件实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。这种策略与前面的策略相比,资源的利用率和系统吞吐量都有很大提高,但是也存在以下缺点: (1)限制了进程对资源的请求,同时给系统中所有资源合理编号也是件困难事,并增加了系统开销; (2)为了遵循按编号申请的次序,暂不使用的资源也需要提前申请,从而增加了进程对资源的占用时间。

死锁的避免

死锁预防是排除死锁的静态策略,它使产生死锁的四个必要条件不能同时具备,从而对进程申请资源的活动加以限制,以保证死锁不会发生。下面我们介绍排除死锁的动态策略–死锁的避免,它不限制进程有关申请资源的命令,而是对进程所发出的每一个申请资源命令加以动态地检查,并根据检查结果决定是否进行资源分配。就是说,在资源分配过程中若预测有发生死锁的可能性,则加以避免。这种方法的关键是确定资源分配的安全性。

银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。

要解释银行家算法,必须先解释操作系统安全状态和不安全状态。

安全序列是指一个进程序列{P1,…,Pn}是安全的,即对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源量之和。

安全状态如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。

不安全状态不存在一个安全序列。不安全状态不一定导致死锁。

算法原理我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。

为保证资金的安全,银行家规定:

(1)当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;

(2)顾客可以分期贷款,但贷款的总数不能超过最大需求量;

(3)当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;

(4)当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.

操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。

银行家算法允许死锁必要条件中的互斥条件,占有且申请条件,不可抢占条件的存在,这样,它与预防死锁的几种方法相比较,限制条件少了,资源利用程度提高了。 这是该算法的优点。其缺点是:

(1)这个算法要求客户数保持固定不变,这在多道程序系统中是难以做到的。

(2)这个算法保证所有客户在有限的时间内得到满足,但实时客户要求快速响应,所以要考虑这个因素。

(3)由于要寻找一个安全序列,实际上增加了系统的开销。

死锁的检测与恢复

一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。

死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。

时间: 2024-10-04 23:42:14

对死锁的探究的相关文章

一次Mutex死锁的原因探究

1.现象 最近项目中调出一个bug,某些时候程序会卡死不动,用windbg进行加载后用 ~*kb 命令列出所有的线程栈调用,发现有多个线程调用 WaitForMultipleObjects 在等待同一个内核对象: 输入 !handle cc f 命令列出该内核对象的详细信息: 发现是是一个Mutex对象,对象名是 Mutex_DebugMsg2 ,查找代码知道这个Mutex是用写log时锁定文件写入用的.代码如下: BOOL CDebugMsg::WriteLogA(LPSTR pszLog)

Mysql索引引起的死锁

提到索引,首先想到的是效率提高,查询速度提升,不知不觉都会有一种心理趋向,管它三七二十一,先上个索引提高一下效率..但是索引其实也是暗藏杀机的... 今天压测带优化项目,开着Jmeter高并发访问项目,后台连着mysql通过show processlist命令查看查询情况,发现些sql语句需要优化,就在关键字段上上了索引.效果很明显项目的吞吐量瞬间提高到原来3倍,但是问题也出现了,日志中报出大量的死锁错误.本来以为程序逻辑有问题,定位了一下程序块,大体逻辑如下: userDao.updateBy

探究SynchronizationContext在.Net异步编程中的地位

原文:探究SynchronizationContext在.Net异步编程中的地位 引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/async异步编程语法糖简化了异步编程方式. 相信很多开发者都看到如下异步编程实践原则:   实践原则  说明  例外情况  ①  避免 Async Void  最好使用 async Task 方法而不是 async void 方法  事件处理程序  ②  始终使用 await  不要混合阻塞式代码和

SqlServer定时备份数据库和定时杀死数据库死锁解决

PS:Sqlserver 2008 R2,windows 8 64位 1.备份数据库 因为要备份,我们就要用到Sqlserver的代理,默认数据库的代理是不开启的.需要我们手动开启的. 执行备份数据库脚本,现在将脚本公布,其实将这一段代码中需要保存的文件路径和数据库名称替换一下就可以实现备份了.但是还没有达到定时备份的目的 ? 1 2 3 4 5 6 7 8 9 10 11 --自动备份并保存最近5天的SQL数据库作业脚本 宋彪 20130310 DECLARE @filename VARCHA

数据库问题5-SYS.SYSPROCESSES使用和查找死锁

http://blog.sina.com.cn/s/blog_62c4727d0100jc5z.html (一)理論部份 sys.sysprocesses (Transact-SQL) http://technet.microsoft.com/zh-tw/library/ms179881.aspx 包含在 SQL Server 執行個體上執行之處理序的相關資訊.這些處理序可以是用戶端處理序或系統處理序.若要存取 sysprocesses,您必須在 master 資料庫內容中,或者,您必須使用 m

55行代码实现Java线程死锁

死锁是Java多线程的重要概念之一,也经常出现在各大公司的笔试面试之中.那么如何创造出一个简单的死锁情况?请看代码: class Test implements Runnable { boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) //这里用while(true)使得线程在这里无限循环,可以避免各种随机情况造成死锁不成功 synchronized(M

死锁现象

死锁发生在当一个服务器和客户端同时试图往一个连接上写东西和同时从一个连接上读的时候.在这种情况下没有进程可以得到任何数据. #!/usr/bin/env python #-*- coding:utf-8 -*- #测试锁死的情况 import socket, traceback host = ''        #主机设为空,程序就可以接收来自任何客户端的连接 port = 51422     #设置端口,选择一个任意大于1024的端口即可 s = socket.socket(socket.AF

mysql死锁问题

开发中遇到这个死锁,阅读了一些博客,但还是没搞明白此死锁的成因,有兴趣的高手可以分析一下,谢谢

线程的同步与死锁

在多线程中,同步与死锁概念很重要,在本章中必须了解以下几点: 1)哪里需要同步. 2)如何实现同步,了解代码即可. 3)及实现同步后有哪些副作用. 代码并不要求可以完整编写,但是概念必须清楚. 具体内容 1.1问题引出 以买火车票为例,不管多少地方可以买火车票,最终一趟列车的车票数量是固定的,如果把各个售票点理解为线程的话,则所有线程应该共同拥有同一份票数. package Thread1; class MyThread implements Runnable{ private int tick