一、什么是死锁
多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题—死锁。
死锁是指两个或两个以上的进程(线程)在运行过程中因争夺资源而造成的一种僵局(Deadly-Embrace) ) ,若无外力作用,这些进程(线程)都将无法向前推进。
下面我们通过一些实例来说明死锁现象。
先看生活中的一个实例,2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃)。
某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都同时占用一个资源,等待另一个资源,这个时候甲在等待乙吃完并释放它占有的筷子,同理,乙也在等待甲吃完并释放它占有的筷子,这样就陷入了一个死循环,谁也无法继续吃饭。。。
在计算机系统中也存在类似的情况。例如,某计算机系统中只有一台打印机和一台输入设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。
这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。
关于死锁的一些结论:
-
参与死锁的进程数至少为两个
-
参与死锁的所有进程均等待资源
-
参与死锁的进程至少有两个已经占有资源
-
死锁进程是系统中当前进程集合的一个子集
-
死锁会浪费大量系统资源,甚至导致系统崩溃。
二、死锁与饥饿
饥饿(Starvation)指一个进程一直得不到资源。
死锁和饥饿都是由于进程竞争资源而引起的。饥饿一般不占有资源,死锁进程一定占有资源。
三、资源的类型
可重用资源和消耗性资源
可重用资源(永久性资源)
可被多个进程多次使用,如所有硬件。
-
只能分配给一个进程使用,不允许多个进程共享。
-
进程在对可重用资源的使用时,须按照请求资源、使用资源、释放资源这样的顺序。
-
系统中每一类可重用资源中的单元数目是相对固定的,进程在运行期间,既不能创建,也不能删除。
消耗性资源(临时性资源)
-
又称临时性资源,是由进程在运行期间动态的创建和消耗的。
-
消耗性资源在进程运行期间是可以不断变化的,有时可能为0。
-
进程在运行过程中,可以不断地创造可消耗性资源的单元,将它们放入该资源类的缓冲区中,以增加该资源类的单元数目。
-
进程在运行过程中,可以请求若干个可消耗性资源单元,用于进程自己消耗,不再将它们返回给该资源类中。
可消耗资源通常是由生产者进程创建,由消费者进程消耗。最典型的可消耗资源是用于进程间通信的消息。
可抢占资源和不可抢占资源
可抢占资源
可抢占资源指某进程在获得这类资源后,该资源可以再被其他进程或系统抢占。对于这类资源是不会引起死锁的。
CPU 和主存均属于可抢占性资源。
不可抢占资源
一旦系统把某资源分配给该进程后,就不能将它强行收回,只能在进程用完后自行释放。
磁带机、打印机等属于不可抢占性资源。
四、死锁产生的原因
-
竞争不可抢占资源引起死锁
-
通常系统中拥有的不可抢占资源,其数量不足以满足多个进程运行的需要,使得进程在运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可抢占资源的竞争 才可能产生死锁,对可抢占资源的竞争是不会引起死锁的。
-
竞争可消耗资源引起死锁
-
进程推进顺序不当引起死锁
-
进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都会因为所需资源被占用而阻塞。
-
信号量使用不当也会造成死锁。进程间彼此相互等待对