信号量机制的不足:

       信号量的控制分布在多个进程中

 正确性分析困难;

  分散的P、V操作:易出错,使用不当可能导致死锁。

 修改、维护困难:易读性差,任一修改都可能影响全局;测试期间发现错误困难,即使发现错误也不容易定位出错位置。

 管程(monitor)机制

 1973年,Hoare和Hanson提出管程思想:

       将共享变量及对共享变量能够进行的所有操作集中在一个模块中。

(把信号量及其操作原语“封装”在一个对象内部)

主要内容

  1. 管程的组成

  2. 管程的特点

  3. 管程的同步控制(条件变量)

       类比生产者—消费者问题

需要封装什么?

  1. 多进程需访问的变量:

buffer,in,out;

empty,full;

  1. 对变量做的操作:

向buffer放/取产品,移动指针in,out;

控制放或取的信号量操作wait、signal;

两类变量,两类操作

生产

……

wait(empty)

wait(mutex)

buffer[in]=产品

in=in+1

signal(mutex)

signal(full)

……

消费

……

wait(full)

wait(mutex)

取buffer[out]

out=out+1

signal(mutex)

signal(empty)

……

 1.管程的组成

  1. 一组局部变量
  2. 对局部变量操作的一组过程
  3. 对局部变量进行初始化的语句。

(联想面向对象中的类)

type p_c=monitor

    var in,out,count: interger;

           buffer: array[0,…,n-1] of item

           notfull,notempty: condition;

—— —— —— —— —— —— —— —— ——

procedure entry put(var product:item)

{}

procedure entry get(var product:item)

{}

—— —— —— —— —— —— —— —— ——

{      in=out=0;

       count=0;              }

  2.管程特点

  任何进程只能通过调用管程提供的过程入口才能进入管程访问共享数据;

  就如同使用临界资源,就要先通过其信号量的申请。

  任何时刻,仅允许一个进程在管程中执行某个内部过程。

  管程如何实现同步?

 对共享变量互斥操作:

              管程的特点直接实现了该要求,进程一次一个进入管程调用内部过程操作共享变量。

  管程的互斥访问完全由编译程序在编译时自动添上,无须程序员关心,能保证正确。

  操作的同步控制:

  靠条件变量的操作管理实现。

              进入管程但不能获取资源操作的过程将阻塞,并在满足条件时被唤醒执行。

type p_c=monitor

    var in,out,count: interger;

           buffer: array[0,…,n-1] of item

           x,y: condition;

procedure entry put(var product:item)

{  if count>=n then x.wait;

    buffer[in]=product;

    in=in+1 mod n;

    count=count+1;

    y.signal;   }

procedure entry get(var product:item)

{  if count<=0 then y.wait;

    nextc=buffer[out];

    out=out-1 mod n;

    count=count-1;

    x.signal;  }

{      in=out=0;

       count=0;              }

生产者-消费者问题的管程解决方法

Producer:

begin

   repeat

  生产an item in nextp;

   p_c.put(nextp);

   until

end

consumer:

begin

   repeat

   p_c.get(nextc);

   消费an item in nextc;

   until

end

  3.条件变量

(主要作用就是进程同步的阻塞和唤醒控制)

  局部于管程的变量有两种:

  普通变量

  条件变量(用于控制进程阻塞和唤醒)

 类似信号量变量,但不取具体值;相当于每个阻塞队列的队列指针。

  对条件变量的操作需结合对普通变量的条件判断,从而控制进程状态。

  * 关于条件变量的操作

  x.wait将执行进程挂到x对应的等待队列上;

  x.signal唤醒x相应的等待队列上的一个进程。

  管程的优点

 保证进程互斥地访问共享变量,并方便地阻塞和唤醒进程。管程可以以函数库的形式实现。相比之下,管程比信号量好控制。

 管程可增强模块的独立性:系统按资源管理的观点分解成若干模块,用数据表示抽象系统资源,使同步操作相对集中,从而增加了模块的相对独立性

  引入管程可提高代码的可读性,便于修改和维护,正确性易于保证:采用集中式同步机制。一个操作系统或并发程序由若干个这样的模块所构成,一个模块通常较短,模块之间关系清晰。

  管程的缺点

大多数常用的编程语言中没有实现管程,如果某种语言本身不支持管程,那么加入管程是很困难的。

虽然大多数编程语言也没有实现信号量,但可将P、V操作作为一个独立的子例程或操作系统的管理程序调用加入。