1、锁的概念
先举一个比较经典的例子:
现在假定有两个人共同养了一条金鱼。该金鱼每天进食一顿。两个人想把金鱼养活,一天只喂一次,也只能喂一次。如果一天内两人都喂了鱼,鱼就胀死。如果一天内两人都没有喂鱼,鱼就饿死。
因为金鱼喂食就会吃掉,两人都是看不到前面是否有人喂过金鱼的。所以在两人互不相通的情况下,这个问题就变得有趣起来。
而这个问题的解决方案,就是锁的原理:设计一种同步措施,使将在任何时候只能有一个人进入放置鱼缸的房间,喂完金鱼后留有纸条,下一个人进去先检查是否有纸条即可。
锁有两个基本操作:闭锁和开锁。
闭锁操作有两个步骤:1、等待锁达到打开状态。2、获得锁并锁上。
开锁操作就是一步:打开锁。
2、发生死锁的原因
以交通阻塞为例,一大堆汽车因为争夺行路权,互不相让而造成阻塞,或者因车辆发生故障抛锚或相撞造成道路阻塞。在这种情况下,所有的车都停下来,谁也无法前行,这就是死锁。
死锁的发生,归根结底是因为对资源的竞争。因为大家都想要某种资源,但又不能随心所欲地得到所有资源,在争夺的僵局中,导致任何人都无法继续推进。
3、死锁的描述
线程的执行要求以某种顺序来使用资源。如果请求被拒绝,那就等着。这种等待有两种应对方式:一是阻塞等待,二是立即返回,执行别的事情,等以后再行请求。如果采用第一种方式,则有可能会发生死锁,因为如果每个线程都在等待某一个资源,因此没有线程可以推进,从而形成死锁。
死锁的定义:如果有一组线程,每个线程都在等待一个事件的发生,而这个事件只能由该组线程里面的另一线程发出,则我们称这组线程发生了死锁。
4、死锁的四个必要条件
条件一:资源有限。即一个系统里面的资源数量有限,以至于无法同时满足所有线程的资源需求。
条件二:持有等待。即一个线程在请求新的资源时,其已经获得的资源并不释放,而是继续持有。
条件三:不能抢占。如果一个资源可以抢占,则死锁也不会发生。
条件四:循环等待条件。这是死锁的最后一个条件,如果你等我、我等你,大家这样都等着对方,就死锁。
5、死锁的应对
死锁应对的两种策略,即:
1、允许死锁发生。
2、不允许死锁发生。
对于第1种策略,其两个子对策为:
1-1、假装没有看见,不予理睬。
1-2、在死锁发生后,想办法予以解决。
对于第2种策略,其两个子对策为:
2-1、通过生活中的周全考虑,避免难题出现。
2-2、通过将发生死锁的必要条件消除,杜绝死锁的发生。
前三种策略(1-1、1-2、2-1)都不能很好的解决死锁问题,只有第四种策略(2-2)可以解决死锁。该策略的中心思想是清除死锁发生的土壤,而死锁发生的土壤就是死锁的四个必要条件。如果消除死锁发生的四个必要条件中的任何一个,则死锁将无法发生。
6、消除死锁的必要条件
1、消除资源独占条件
解决办法:将资源无限增加或把所有资源变为共享。
资源不能无限增加,因为资源是有限的,没有什么东西是无限的。而很多资源又不能共享,因此消除资源独占条件行不通
。
2、消除保持和请求条件
解决办法:一个进程必须一次请求其所需要的所有资源。
一次将所有资源拿上,太过浪费。因为有的资源要到最后才需要,但也得在一开始就占用,显然不利于资源的有效利用。因此消除保持和请求条件行不通
。
3、消除非抢占条件
解决办法:允许对资源进行抢占。
该策略有局限性。因为不是所有的资源都可以被抢占而不产生不良后果。例如,锁 就不能抢占,如果从一个进程手上将锁抢过来,后果会不堪设想。
4、消除循环等待条件
解决办法:规定资源的使用必须按照设定的顺序请求。
该策略打断了循环等待的死锁条件,无法发生死锁。
7、死锁的思考-综合治理
四种策略各有优缺点,但总体说来,检测修复与动态避免两种策略成本过高(实现的程序复杂性成本和运行时的时间成本),很难在实际系统中采用。静态防止与不予理睬是较为合理的策略。
用过Windows和Linux操作系统的人几乎没有不经历死锁的。解决死锁的办法也很简单:重新启动系统或者停止部分进程,至于重启或停止进程所造成的不良后果则只能由用户承担了。