4.2.6 管程机制

采用信号量机制实现进程的并发控制,存在一些问题:

1)同步操作分散在各个进程中,使用不当就可能导致死锁。例如P、V操作的次序错误、重复或遗漏,特别是当有分支语句时,就有多条路径,此时,其中某条路径可能存在P、V操作的重复或遗漏等。

2)可读性差。因为要了解对于一组共享变量及信号量的操作是否正确,必须通读整个系统或者并发程序。

3)不利于修改和维护。模块的独立性差,任一组变量或一段代码的修改都可能影响全局。

4)正确性难以保证。操作系统或并发程序通常很大,很难保证这样一个复杂的系统没有逻辑错误。

为了解决这些问题,1973年Hoare和Hanson提出了管程这种集中式同步机制。其基本思想是将信号量及其操作原语封装在一个对象内部,即将共享变量以及对共享变量能够进行的所有操作集中在一个模块中。

1.管程的定义

管程是管理进程间同步的机制,它保证进程互斥地访问共享变量,并方便地阻塞和唤醒进程。管程可以函数库的形式实现。相比之下,管程比信号量好控制,可以解决使用信号量机制存在一些问题。

将管程定义为:是关于共享资源的数据结构,和一组针对该资源的操作过程所构成的软件模块。

一个操作系统或并发程序由若干个这样的模块构成,由于一个模块通常较短,模块之间关系清晰,提高了可读性,便于修改和维护,正确性易于保证。

2.管程的组成部分

管程的组成部分包括管程名称、数据结构说明、对该数据结构进行操作的一组过程/函数和初始化语句。

3.管程的主要特征

1)模块化:一个管程是一个基本程序单位,可以单独编译。

2)抽象数据类型:管程是一种特殊的数据类型,其中不仅有数据,而且有对数据进行操作的代码。

3)信息掩蔽:管程是半透明的,管程中的过程(函数)实现了某些功能,但这些功能是如何实现的,外部则是不可见的。

4.管程的属性

1)共享性:管程中的过程可被所有要调用管程中过程的进程所共享。

2)互斥性:为了保证管程共享变量的数据完整性,规定管程互斥进入,即进程需要互斥地调用内部过程进入管程。

3)安全性:管程中的共享变量在管程外部是不可见的,外部只能通过调用管程中的内部过程(函数)间接访问管程中的共享变量。

5.引入条件变量的同步机制

管程通过防止对一个资源的并发放访问,实现了互斥。它还需要引入同步工具使得进程因资源无法满足而无法继续运行时被阻塞,因而在管程中应当设有进程等待队和相应的等待及唤醒操作。

管程实现同步是通过设置条件变量以及在条件变量上进行操作的两个同步原语wait和signal。wait使调用进程等待,并将它排在相应的等待队列上;signal唤醒等待队列的队首进程。

6.Hoare的管程实现方法

当管程过程P发现自己无法继续运行下去时,会对某个条件变量执行wait操作,导致自己阻塞,将另一个等待在管程外的进程Q调入管程,这种自身阻塞直到管程中另一个进程对同一个条件变量执行signal操作而被解除。此时,进程Q唤醒了进程P,如何避免管程中同时存在两个活跃进程?即需要一条规则来决定signal操作之后应该怎么办?

Hoare采用的策略是,让唤醒的进程P运行,Q进程阻塞自己而等待进程P的退出或阻塞。该策略的优点是逻辑性强,缺点是进程切换比较频繁,实现效率较低。