死锁的概念
什么是死锁
在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推进的现象,就是“死锁”。发生死锁后若无外力干涉,这些进程都将无法向前推进
进程死锁、饥饿、死循环的区别
死锁:各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象
饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象
死循环:某进程执行过程中一直跳不出某个循环的现象。有时是因为程序逻辑bug导致的,有时是程序员故意设计的
死锁产生的必要条件
产生死锁必须同时满足以下四个条件,只要有其中任一条件不成立,死锁就不会发生
- 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备等),像内存、扬声器这种可以同时让多个进程使用的资源是不会导致死锁的
- 不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放
- 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放
- 循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求
注意:发生死锁时一定有循环等待,但是发生循环等待时未必死锁(循环等待是死锁的必要不充分条件)
什么时候会发生死锁
死锁的处理策略
- 预防死锁(静态策略,不允许死锁发生):破坏死锁产生的四个必要条件中的一个或几个
- 避免死锁(动态策略,不允许死锁发生):用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)
- 死锁的检测和解除:允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁
死锁的处理策略:预防死锁
破坏互斥条件
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁
如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如SPOOLing技术,操作系统可以采用SPOOLing技术把独占设备在逻辑上改造成共享设备
该策略的缺点:并不是所有的资源都可以改造成可共享使用的资源。并且为了系统安全,很多地方还必须保护这种互斥性,因此,很多时候都无法破坏互斥条件
破坏不剥夺条件
破坏请求和保持条件
C类进程可能会饥饿:
破坏循环等待条件
死锁的处理策略:避免死锁(银行家算法)
什么是安全序列
所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要能找出一个安全序列,系统就是安全状态。当然,安全序列可能有多个
什么是系统的不安全状态,与死锁有何联系
如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了不安全状态。这就意味着之后可能所有进程都无法顺利的执行下去。当然,如果有进程提前归还了一些资源,那系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑到最坏的情况
❗️如果系统处于安全状态,就一定不会发生死锁。如果系统进入不安全状态,就可能发生死锁(处于不安全状态未必就是发生了死锁,但发生死锁时一定是在不安全状态)
因此可以在资源分配之前预先判断这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求。这也是“银行家算法”的核心思想
如何避免系统进入不安全状态:银行家算法
银行家算法是荷兰学者Dijkstra为银行系统设计的,以确保银行在发放现金贷款时,不会发生不能满足所有客户需要的情况。后来该算法被用在操作系统中,用于避免死锁
核心思想:在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待
死锁的处理策略:死锁的检测和解除
死锁的检测
用于检测系统状态,以确定系统中是否发生了死锁
最终还连着边的那些进程就是处于死锁状态的进程:
死锁的解除
当认定系统中已经发生了死锁,利用该算法可将系统从死锁状态中解脱出来
一旦检测出死锁的发生,就应该立即解除死锁
❗️并不是系统中所有的进程都是死锁状态,用死锁检测算法化简资源分配图后,还连着边的那些进程就是死锁进程
如何决定先剥夺哪个进程的资源或先对谁动手?
- 根据进程优先级(先动手优先级低的)
- 根据进程已执行多长时间
- 根据进程还要多久能完成
- 根据进程已经使用了多少资源(先动手使用资源多的,这样很容易把更多死锁进程解除出来)
- 根据进程是交互式的还是批处理式的(优先动手批处理式的,交互式的是跟用户打交道)