Skip to content

Latest commit

 

History

History
86 lines (63 loc) · 7.86 KB

49 进程管理7-死锁.md

File metadata and controls

86 lines (63 loc) · 7.86 KB

#操作系统

[30] 管程

为什么要引入管程

信号量机制存在的问题:编写程序困难、易出错。1973年,Brinch Hansen 首次在程序设计语言 (Pascal) 中引入了“管程”成分——一种高级同步机制。

特点

管程(Monitor)是一种特殊的软件模块,有这些部分组成:

  1. 局部于管程的共享数据结构说明;
  2. 对该数据结构进行操作的一组过程(函数抽象);
  3. 对局部于管程的共享数据设置初始值的语句;
  4. 管程有一个名字。

管程的基本特征:

  1. 局部于管程的数据只能被局部于管程的过程所访问;
  2. 一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
  3. 每次仅允许一个进程在管程内执行某个内部过程

目的

引入管程的目的无非就是要更方便地实现进程互斥和同步。

  1. 需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
  2. 需要在管程中定义用于访问这些共享数据的“入口”——其实就是一些函数(如生产者消费者 问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
  3. 只有通过这些特定的“入口”才能访问共享数据
  4. 管程中有很多“入口”,但是每次只能开放其中一个“入口”,并且只能让一个进程或线程进 入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证一 个时间段内最多只会有一个进程在访问缓冲区。注意:这种互斥特性是由编译器负责实现的, 程序员不用关心)
  5. 可在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量 上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”);可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。

[31] 死锁的概念

死锁

  1. 死锁(deadlock),是指各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象。
  2. 饥饿(hunger),是由于长期得不到想要的资源,某进程无法向前推进的现象。比如:在短进程优先(SPF)算法 中,若有源源不断的短进程到来,则长进程将一直得不到处理机,从而发生长进程“饥饿”。
  3. 死循环(dead loop),是某进程执行过程中一直跳不出某个循环的现象。有时是因为程序逻辑 bug 导致的,有时是 程序员故意设计的。

这三者都是都是进程无法顺利向前推进的现象 (故意设计的死循环除外)。

现象 区别
死锁 死锁一定是“循环等待对方手里的资源”导致的,因此如果有死锁现象,那至少有两个或两个以上的进程同时发生死锁。另外,发生死锁的进程一定处于阻塞态。
饥饿 可能只有一个进程发生饥饿。发生饥饿的进程既可能是阻塞态(如长期得不到 需要的I/O设备),也可能是就绪态(长期得不到处理机)
死循环 可能只有一个进程发生死循环。死循环的进程可以上处理机运行(可以是运行 态),只不过无法像期待的那样顺利推进。死锁和饥饿问题是由于操作系统分 配资源的策略不合理导致的,而死循环是由代码逻辑的错误导致的。

死锁和饥饿是管理者(操作系统)的问题,死循环是被管理者的问题。

死锁的必要条件

产生死锁必须同时满足一下四个条件,只要其中任一条件不成立,死锁就不会发生。

  1. 互斥条件(Mutual Exclusion):只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。 像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待 这种资源)。
  2. 不剥夺条件(No Preemption):进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
  3. 请求和保持条件(Hold and Wait):进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请 求进程被阻塞,但又对自己已有的资源保持不放。
  4. 循环等待条件(Circular wait):存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。

注意!发生死锁时一定有循环等待,但是发生循环等待时未必死锁(循环等待是死锁的必要不充分条件)。

死锁的处理策略

  1. 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。
  2. 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法) 。
  3. 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁。

[32] 预防死锁

死锁的产生必须满足四个必要条件,只要其中一个或者几个条件不满足,死锁就不会发生。

破坏互斥条件

如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如: SPOOLing技术。 操作系统可以采用 SPOOLing 技术把独占设备在逻辑上改造成共享设备。比如,用 SPOOLing 技术将打印机改造为共享设备,使用共享队列的技术,将设备资源虚拟化共享。

该策略的缺点:并不是所有的资源都可以改造成可共享使用的资源。并且为了系统安全,很多地方还必须保护这种互斥性。因此,很多时候都无法破坏互斥条件

破坏不剥夺条件

  • 方案一:当某个进程请求新的资源得不到满足时,它必须立即释放保持的所有资源,待以后需要时再重新申请。也就是说,即使某些资源尚未使用完,也需要主动释放,从而破坏了不可剥夺条件。
  • 方案二:当某个进程需要的资源被其他进程所占有的时候,可以由操作系统协助,将想要的资源强行剥夺。这种方式一般需要考虑各进程的优先级(比如:剥夺调度方式,就是将处理机资源强行剥夺给优先级更高的进程使用)

破坏请求和保持条件

进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进 程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。 可以采用静态分配方法,即进程在运行前一次申请完它所需要的全部资源,在它的资源未满足前, 不让它投入运行。一旦投入运行后,这些资源就一直归它所有,该进程就不会再请求别的任何资源 了。

破坏循环等待条件

可采用顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源, 同类资源(即编号相同的资源)一次申请完。 原理分析:一个进程只有已占有小编号的资源时,才有资格申请更大编号的资源。按此规则,已持 有大编号资源的进程不可能逆向地回来申请小编号的资源,从而就不会产生循环等待的现象。

[33] 避免死锁(银行家算法)

[34] 死锁的检测和解除