产业气象站|写给大忙人看的死锁全详解


产业气象站|写给大忙人看的死锁全详解
文章图片
计算机系统中有很多独占性的资源 , 在同一时刻只能每个资源只能由一个进程使用 , 我们之前经常提到过打印机 , 这就是一个独占性的资源 , 同一时刻不能有两个打印机同时输出结果 , 否则会引起文件系统的瘫痪 。 所以 , 操作系统具有授权一个进程单独访问资源的能力 。
两个进程独占性的访问某个资源 , 从而等待另外一个资源的执行结果 , 会导致两个进程都被阻塞 , 并且两个进程都不会释放各自的资源 , 这种情况就是死锁(deadlock) 。
死锁可以发生在任何层面 , 在不同的机器之间可能会发生死锁 , 在数据库系统中也会导致死锁 , 比如进程A对记录R1加锁 , 进程B对记录R2加锁 , 然后进程A和B都试图把对象的记录加锁 , 这种情况下就会产生死锁 。
下面我们就来讨论一下什么是死锁、死锁的条件是什么、死锁如何预防、活锁是什么等 。
首先你需要先了解一个概念 , 那就是资源是什么
资源
大部分的死锁都和资源有关 , 在进程对设备、文件具有独占性(排他性)时会产生死锁 。 我们把这类需要排他性使用的对象称为资源(resource) 。 资源主要分为可抢占资源和不可抢占资源
可抢占资源和不可抢占资源
资源主要有可抢占资源和不可抢占资源 。 可抢占资源(preemptableresource)可以从拥有它的进程中抢占而不会造成其他影响 , 内存就是一种可抢占性资源 , 任何进程都能够抢先获得内存的使用权 。
不可抢占资源(nonpreemtableresource)指的是除非引起错误或者异常 , 否则进程无法抢占指定资源 , 这种不可抢占的资源比如有光盘 , 在进程执行调度的过程中 , 其他进程是不能得到该资源的 。
死锁与不可抢占资源有关 , 虽然抢占式资源也会造成死锁 , 不过这种情况的解决办法通常是在进程之间重新分配资源来化解 。 所以 , 我们的重点自然就会放在了不可抢占资源上 。
下面给出了使用资源所需事件的抽象顺序
产业气象站|写给大忙人看的死锁全详解
文章图片
如果在请求时资源不存在 , 请求进程就会强制等待 。 在某些操作系统中 , 当请求资源失败时进程会自动阻塞 , 当自资源可以获取时进程会自动唤醒 。 在另外一些操作系统中 , 请求资源失败并显示错误代码 , 然后等待进程等待一会儿再继续重试 。
请求资源失败的进程会陷入一种请求资源、休眠、再请求资源的循环中 。 此类进程虽然没有阻塞 , 但是处于从目的和结果考虑 , 这类进程和阻塞差不多 , 因为这类进程并没有做任何有用的工作 。
请求资源的这个过程是很依赖操作系统的 。 在一些系统中 , 一个request系统调用用来允许进程访问资源 。 在一些系统中 , 操作系统对资源的认知是它是一种特殊文件 , 在任何同一时刻只能被一个进程打开和占用 。 资源通过open命令进行打开 。 如果文件已经正在使用 , 那么这个调用者会阻塞直到当前的占用文件的进程关闭文件为止 。
资源获取
对于一些数据库系统中的记录这类资源来说 , 应该由用户进程来对其进行管理 。 有一种管理方式是使用信号量(semaphore) 。 这些信号量会初始化为1 。 互斥锁也能够起到相同的作用 。
这里说一下什么是互斥锁(Mutexes):在计算机程序中 , 互斥对象(mutex)是一个程序对象 , 它允许多个程序共享同一资源 , 例如文件访问权限 , 但并不是同时访问 。 需要锁定资源的线程都必须在使用资源时将互斥锁与其他线程绑定(进行加锁) 。 当不再需要数据或线程结束时 , 互斥锁设置为解锁 。下面是一个伪代码 , 这部分代码说明了信号量的资源获取、资源释放等操作 , 如下所示
typedefintsemaphoresemaphoreaResourcevoidprocessA(void){down(&ampaResource)useResource()up(&ampaResource)}