操作系统死锁概念

在多道程序环境下,多道程序就是是在计算机内存中同时存放几道相互独立的程序,使它们在管理程序控制之下,相互穿插的运行,多个进程可能会竞争一定数量的资源,某个进程去申请资源去完成任务,如果这个时候资源不可用的话,那么该进程就会进入等待的状态,如果所申请的资源被其他等待的进程所占有了,那么该等待进程有可能再也无法改变其的状态

资源的定义

资源类型有内存空间、CPU周期、文件、I/O设备(打印机和DVD驱动器等),资源可以有多个,就比如说我可以有两个CPU,可以有两个打印机

资源的申请和释放为系统调用,比如说系统调用:request()/release() (设备)、open()/close() (文件)、allocate()/free() (内存)。其他资源的释放的申请和释放可以通过信号量的wait与signal操作或者通过互斥锁的获取与释放来完成,所以对于进程或现场的每次使用,操作系统都会去检查以确保使用进程已经申请并且获取了资源。系统表会去记录每个资源是否空闲或者是否已经被分配了。如果进程所申请的资源正在为其他进程所使用,那么该进程就会被增加到该资源的等待队列。

死锁状态

当一组进程中的每个进程都在等待一个事件,而这一事件只能由这一组进程的另一进程引起,那么这组进程就处于死锁状态。当出现死锁的时候,进程永远不能完成,而且系统资源会被阻碍使用,阻止了其他作业开始执行

死锁出现的必要条件

  • 互斥:至少一个资源必须处于非共享模式,也就是是说一次只有一个进程在使用,如果另一个进程申请该资源,那么申请的进程就必须等到该资源被释放为止
  • 占有并等待:一个进程必须占有占有一个资源,并等待另外一个资源,就比如说我需要内存空间这是一个资源,我还需要打印机,内存空间这一资源我已经申请到,但是我打印机资源却申请不到一直被其他进程所占有,所以我就需要等待
  • 非抢占:资源不能被抢占,即资源只能在进程完成任务后自动释放
  • 循环等待,比如说A等待B,B等待A

如果我们在多线程的程序当中对于互斥锁使用不当的话就可能会导致死锁,Pthread就提供了有关互斥锁的API比如说pthread_mutex_init就是互斥锁的初始化函数,互斥锁可以通过pthread_mutex_lock()和pthread_mutex_unlock去释放

下面就是利用互斥锁,形成的死锁
这里写图片描述

死锁处理,这里讲下三种方法

  • 可以去使用协议以此预防或者去避免死锁,确保系统不会进入死锁的状态
  • 可以允许系统进入死锁状态,然后去检测它,并且去解决死锁问题
  • 可以忽略这个问题,认为死锁不可能再系统内发生

这里第三种方法被绝大多数的操作系统所采用,包括Unix和Windows,因为个人计算机上面,其实发生死锁也没有很大的问题,大不了我直接进程管理器直接关闭进程好了。所以应用程序的开发人员需要自己去处理死锁

当然上面的死锁处理方法如果就这些基本方法肯定是不够的,所以我们常常将其组合起来,然后选出最佳方案再进行处理

死锁避免

死锁避免的方法其实可以要求操作系统事先得到有关进程申请资源和使用资源的额外信息。有了这些额外信息,系统就可以去确定对于一个申请,进程是否应该等待,为了确定当前申请是允许还是延迟,系统必须去考虑现在有的可用的资源、已分配给每个进程的资源、每一个进程将来申请和释放的资源。

死锁预防

通过抑制死锁发生的必要条件就是通过限制资源申请的方法来预防死锁,下面通过对死锁发生的4个必要条件展开说明

  • 互斥:共享资源不要求互斥访问,非共享资源必须要有互斥条件
  • 占有并等待:必须保证进程申请资源的时候,没有占有其他资源,也就是说要求进程在执行前一次性申请全部资源,就比如说我有一个任务需要打印机,DVD驱动器,磁盘文件,执行这个任务前全部申请。还有种方法就是允许进程可以申请一些资源并且去使用它们,但是在它要申请更多资源的时候,它必须释放现在已经分配的所有资源,就比如说进程在开始的时候只去申请DVD驱动器和磁盘文件,在做完这个步骤之后再去申请打印机,这样的缺点就是资源利用率低,可能会发生饥饿
  • 非抢占:当然变成抢占啊,就比如说一个进程的申请没有实现,那么现在已经分配的资源都可以被抢占,抢占的资源被放入进程等待的资源链表当中,只有当进程获得其原有资源和所申请的新的资源的时候,进程才可以重新执行,通常应用于可以保存和恢复的资源比如说CPU寄存器和内存
  • 循环等待:对所有资源类型进行排序,然后要求进程按照递增的顺序申请资源

死锁恢复

当死锁检测算法确定死锁已经存在了,那么我们可以通知操作人员死锁已经发生,这样可以让操作人员人工处理死锁,还有种方法就是让系统从死锁状态中自动恢复过来,打破死锁的方法其实有两种方法一种方法就是简单地终止一个或者多个进程以打破循环等待,另一个方法就是从一个或者多个死锁进程那边抢占一个或者是多个资源

关于进程终止打破死锁的方法有下面两种形式

  • 终止所有死锁进程,这样的话代价比较高,因为有些进程可能计算了很长时间,这些计算结果必须放弃,以后还可以重新计算
  • 一次只是去终止一个进程,直到取消死锁循环为止,这种方法的开销也会比较大,因为每次终止一个进程,都必须调用死锁循环为止

如果采用抢占资源的话我们可以逐步的从进程中抢占资源给其他进程使用,直到死锁的环被打破为止,如果选择用抢占来解决死锁,有三个问题我们必须考虑

  • 选择一个牺牲品:抢占哪些资源和哪个进程?我们必须要去确定抢占顺序以使代码最小化,代价因素包括死锁进程所拥有的资源数量,死锁进程到现在为止在其执行过程中所消耗的时间
  • 回滚:如果从一个进程中抢占到了一个资源,那么我们应该对该进程做回滚操作,不然的话该进程不能正常执行,因为它缺少所需要的资源,必须要将进程回滚到某个安全的状态,然后之后就可以以这个状态重新启动进程
  • 饥饿:怎么去保证资源不会总是从同一个进程中被抢占,如果系统总是基于代码来选择牺牲的进程,那么同一个进程可能总是会被选为牺牲品,那么显然这个任务是永远不可能完成其指定的任务的,所以系统肯定是需要去处理这种饥饿状态的,我们可以考虑加上进程的优先级,每隔一段时间,加优先级

死锁避免方法要比预防的算法要求低,只需要去了解进程的使用资源的情况就可以了,采取,银行家算法只需要知道每个进程所请求的每种资源的最大数量,就可以进行死锁的避免

猜你喜欢

转载自blog.csdn.net/zcmuczx/article/details/80283930