管程
管程概念的提出
- 管程试图抽象相关并发进程对共享变量的访问,以提供一个友善的并发程序设计开发环境(信号量机制的不足:程序编写困难、易出错)
- 管程是由若干公共变量及其说明和所有访问这些变量的过程所组成
- 管程把分散在各个进程中互斥地访问公共变量的那些临界区集中起来管理,管程的局部变量只能由该管程的过程存取
- 进程只能互持地调用管程中的过程
管程的定义
管程是由局部于自己的若干公共变量及其说明和所有访问这些公共变量的过程所组成的软件模块
管程的属性
- 共享性
- 安全性
- 互斥性
管程的形式
type 管程名=monitor{
局部遍历说明;
条件变量说明;
初始化语句;
define 管程内定义的,管程外可调用的过程或函数名列表;
use 管城外定义的,管程内将调用的过程或函数名列表;
过程名/函数名(形式参数列表) {
<过程/函数体>;
}
···
过程名/函数名(形式参数列表) {
<过程/函数体>;
}
}
管程的条件变量
- 条件变量(condition variables):当调用管程过程的进程无法运行时,用于阻塞进程的信号量
- 同步原语wait:当一个管程过程发现无法继续时(如发现没有可用资源时),它再某些条件变量上执行wait,这个动作引起调用进程阻塞
- 同步原语signal:用于释放在条件变量上阻塞的进程
管程的执行模型
管程过程执行中signal的处理问题
- 当使用signal释放一个等待进程时,可能出现两个进程同时停留在管程内。解决办法:
- 执行signal的进程等待,直到被释放进程退出管程或等待另一个条件
- 被释放进程等待,直到执行signal的进程退出管程或等待另一个条件
- 霍尔采用了第一种办法
- 汉森选择了两者的这种,规定管程过程所执行的signal操作是过程体的最后一个操作
霍尔管程
实现方法
- 使用signal释放一个等待进程时,霍尔管程让执行signal的进程等待,直到被释放进程退出管程或等待另一个条件
- 霍尔管程基于PV操作原语实现
- Wait和signal可以是程序过程
- 可以用语言机制实现霍尔管程
互斥调用霍尔管程的信号量
TYPE interf = RECORD
mutex: semaphore; // 调用管程前使用的互持信号量
next: semaphore; // 发出signal的进程挂起自己的信号量
next_count: integer;// 在next上等待的进程数
END;
互持调用霍尔管程的框架
P(IM.mutex);
<过程体>;
if IM.next_count > 0 then
V(IM.next);
else
V(IM.mutex);
霍尔管程的条件变量
x_sem: semaphore; // 与资源相关的信号量
x_count: integer; // 在x_sem上等待的进程数
霍尔管程的wait过程
procedure wait(var x_sem: semaphore, var x_count: integer, var IM: interf);
begin
x_count := x_count + 1;
if IM.next_count > 0 then V(IM.next);
else V(IM.mutex);
P(x_sem);
x_count := x_count - 1;
end;
霍尔管程的signal过程
procedure signal(var x_sem: semaphore, var x_count: integer, var IM: interf);
begin
if x_count > 0 then begin
IM.next_count := IM.next_count + 1;
V(x_sem);
P(IM.next); // 进入等待调用管程的队列
IM.next_count := IM.next_count - 1;
end;
end;
例
读者写者问题
有两组并发进程:读者与写者,共享一个文件,要求:
- 允许多个读者同时执行读操作
- 任一写者出现后,新的读者与写者均被拒绝
- 写者在完成写操作之前不允许其他读者和写者工作
- 写者欲工作,要等待已存在的读者完成读操作
关键:
- 等待读的进程与计数;等待写的进程与计数
- 正在读的进程技术;正在等待写的进程计数
代码: