管程 (英语:Moniters,也称为监视器) 是一种程序结构,结构内的多个子程序(对象或模块)形成的多个工作线程互斥访问共享资源。这些共享资源一般是硬件设备或一群变量。管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。
管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。
管程是东尼·霍尔 [1] 与泊·派克·汉森 [2]提出的,并由泊·派克·汉森首次在并行Pascal中实现。东尼·霍尔证明了这与信号量是等价的。管程在当时也被用于单操作系统环境中的进程间通信。
在编程语言Concurrent Pascal,Pascal-Plus,Modula-2,Modula-3,Mesa以及Java中都提供这个功能。
一个管程包含:
一个管程的程序在运行一个线程前会先取得互斥锁,直到完成线程或是线程等待某个条件被满足才会放弃互斥锁。若每个执行中的线程在放弃互斥锁之前都能保证不变量成立,则所有线程皆不会导致竞态条件成立。
以下这个银行账户的提款/存款事务的管程是个简单的例子:
monitor class Account { private int balance := 0 invariant balance >= 0 public method boolean withdraw(int amount) precondition amount >= 0 { if balance < amount then return false else { balance := balance - amount ; return true } } public method deposit(int amount) precondition amount >= 0 { balance := balance + amount } }
当一个线程执行管程中的一个子程序时,称为占用(occupy)该管程. 管程的实现确保了在一个时间点,最多只有一个线程占用了该管程。这是管程的互斥锁访问性质。
当线程要调用一个定义在管程中的子程序时,必须等到已经没有其它线程在执行管程中的某个子程序。
在管程的简单实现中,编译器为每个管程对象自动加入一把私有的互斥锁。该互斥锁初始状态为解锁,在管程的每个公共子程序的入口给该互斥锁加锁,在管程的每个公共子程序的出口给该互斥锁解锁。
这个例子中的不变量是“任何操作运行前 balance 变量必须反映正确的余额”。一般而言,不变量的条件不被写在程序中,而在注解中有相关说明,然而Eiffel程序设计语言检查不变量。
管程作为一个模块,它的类型定义如下:
monitor_name = MoNITOR;
共享变量说明;
define 本管程内部定义、外部可调用的函数名表;
use 本管程外部定义、内部可调用的函数名表;
内部定义的函数说明和函数体
{
共享变量初始化语句;
}