在多道程序系统中,同时有多个进程并发运行,共享系统资源,从而提高了系统资源利用率,提高了系统的处理能力。但是,若对资源的管理、分配和使用不当,则会产生死锁或是饥饿。所谓死锁是指在多道程序系统中,一组进程中的每一个进程军无限期等待被该组进程中的另一个进程所占有且永远不会释放的资源。饥饿是指系统不能保证某个进程的等待时间上界,从而使该进程长时间等待,当等待时间给进程推进和响应带来明显影响时,称发生了进程饥饿。当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时称该进程被饿死。下面我们就来分别讨论一下死锁与饥饿各自的特点。
首先是死锁。
产生死锁的原因主要有两个,一是竞争资源,系统提供的资源数量有限,不能满足每个进程的需求;二是多道程序运行时,进程推进顺序不合理。由此可见,发生死锁时死锁进程的个数至少是两个。我们可以举一个最简单的例子来了解一下死锁:
P1 | P2 |
… | … |
Request(A) | Request(B) |
Request(B) | Request(A) |
Request(B) | Request(A) |
Request(A) | Request(B) |
假如双方都拥有部分资源(P1拥有A,P2拥有B,且A,B均只有一个),但这时P1还需要B,P2还需要A,于是P1与P2都会处在无限等待状态,发生了死锁。
由这个例子,我们可以归纳分析出产生死锁的必要条件:
(1) 互斥条件
资源是独占的且排他使用。即任意时刻一个资源只能给一个进程使用,其他申请者只有等待,直到资源被占有者释放。如例子中的A,B资源。
(2) 不可剥夺条件
进程所获得的资源在未使用完毕之前,不能被其他进程强行剥夺,而只能由拥有该资源的进程自愿释放。如例子中P2 不能强占P1拥有的A资源,而P1也不能强占P2拥有的B资源。
(3) 请求和保持条件
进程每次申请他所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。如例子中P1申请B资源时继续占有A资源,P2申请A资源时继续占有B资源。
(4) 循环等待条件
在发生死锁时,必然存在一个进程等待环路,环路中的每一个进程已占有的资源同时被另一个进程所申请。如例子中的P1和P2就是一个简单的等待环路。
系统发生死锁不仅浪费了大量的系统资源,甚至会导致整个系统的崩溃,因此如何解决死锁问题是操作系统设计中的一个重点。目前主要有两类方法,一类是不让死锁发生;另一类是让死锁发生,再加以解决。
死锁预防就是力图不让死锁发生,它采用破坏“不可剥夺”条件,或破坏“请求保持”条件,或破坏“循环等待”条件来达到目的,但这种方法给系统加上了较强的限制条件,严重的影响了系统性能。死锁避免则是不破坏死锁的必要条件,而是系统对进程发出的每一个系统能够满足的资源申请进行动态检验,并根据检验结果决定是否分配资源,如果分配后系统可能发生死锁,则不分配,否则分配。
这种方法算法复杂,会消耗很多的系统时间。
死锁的检测与解除则属于让死锁发生,再加以解决的方法。操作系统不断的监督进程的进展路径,一旦检测到死锁的发生,则采用专门的措施解除死锁,并以最小的代价使整个系统恢复正常。
以上大概介绍了死锁的特点和一些关于死锁的处理方法。下面看一下饥饿:
产生饥饿的主要原因是:在一个动态系统中,对于每类系统资源,操作系统需要确定一个分配策略,当多个进程同时申请某类资源时,由分配策略确定资源分配给进程的次序。有时资源分配策略可能是不公平的,即不能保证等待时间上界的存在。在这种情况下,即使系统没有发生死锁,某些进程也可能会长时间等待.当等待时间给进程推进和响应带来明显影响时,称发生了进程饥饿,当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时称该进程被饿死。举个例子,当有多个进程需要打印文件时,如果系统分配打印机的策略是最短文件优先,那么长文件的打印任务将由于短文件的源源不断到来而被无限期推迟,导致最终的饥饿甚至饿死。
饥饿没有其产生的必要条件,随机性很强。并且饥饿可以被消除,因此也将忙式等待时发生的饥饿称为活锁。
由于饥饿和饿死与资源分配策略有关,因而解决饥饿与饿死问题可从资源分配策略的公平性考虑,确保所有进程不被忽视。如时间片轮转算法(RR)。它将CPU的处理时间分成一个个时间片,就绪队列中的诸进程轮流运行一个时间片,当时间片结束时,就强迫运行程序让出CPU,该进程进入就绪队列,等待下一次调度。同时,进程调度又去选择就绪队列中的一个进程,分配给它一个时间片,以投入运行。如此方式轮流调度。这样就可以在不考虑其他系统开销的情况下解决饥饿的问题。
最后,我们来比较的看一下死锁与饥饿。
死锁与饿死有一定相同点:二者都是由于竞争资源而引起的。但又有明显差别:
(1) 从进程状态考虑,死锁进程都处于等待状态,忙式等待(处于运行或就绪状态)的进程并非处于等待状态,但却可能被饿死;
(2) 死锁进程等待永远不会被释放的资源,饿死进程等待会被释放但却不会分配给自己的资源,表现为等待时限没有上界(排队等待或忙式等待);
(3) 死锁一定发生了循环等待,而饿死则不然。这也表明通过资源分配图可以检测死锁存在与否,但却不能检测是否有进程饿死;
(4) 死锁一定涉及多个进程,而饥饿或被饿死的进程可能只有一个。
(5)在饥饿的情形下,系统中有至少一个进程能正常运行,只是饥饿进程得不到执行机会。而死锁则可能会最终使整个系统陷入死锁并崩溃。
总之,死锁和饥饿是操作系统中亟待解决的重要问题,发明出一个令人满意的完善的解决方法是一个诱人的且永远不会过时的课题。