同步互斥机制和通信机制
- 管程monitor
- 进程间通信 Inter-Process Communication
- 典型操作系统的IPC机制
管程 monitor
为什么会出现管程?
问题:信号量机制的不足:程序编写困难、易出错
解决:Brinch Hansen(1973) Hoare(1974)
方案:在程序设计语言中引入管程成分;一种高级同步机制
管程的定义
是一个特殊的模块;有一个名字;由关于共享资源的数据结构及在其上操作的一组过程组成。
进程与管程:进程只能通过调用管程中的过程来间接地访问管程中的数据结构。
管程要保证什么?
作为一种同步机制,管程要解决两个问题:
- 互斥:管程是互斥进入的——为了保证管程中的数据结构的数据完整性;管程的互斥性是由编译器负责保证的。
- 同步:管程中设置条件变量及等待/唤醒操作以解决同步问题;可以让一个进程或线程在条件变量上等待(此时,应先释放管程的使用权),也可以通过发送信号将等待在条件变量上的进程或线程唤醒。
应用管程时遇到的问题:
设问:是否会出现这样一种场景:有多个进程同时在管程中出现?
场景:当一个进入管程的进程执行等待操作时,它应当释放管程的互斥权。当后面进入管程的进程执行唤醒操作时(例如P唤醒Q),管程中便存在两个同时处于活动状态的进程。
如何解决:
三种处理方法: - P等待Q执行 Hoare
- Q等待P继续执行 MESA
- 规定唤醒操作作为管程中最后一个可执行的操作 Hansen,并发Pascal
HOARE管程
HOARE管程说明
因为管程是互斥进入的,所以当一个进程试图进入一个已被占用的管程时,应当在管程的入口处等待;为此管程的入口处设置一个进程等待队列,称作入口等待队列。
如果进程P唤醒进程Q,则P等待Q执行;如果进程Q执行中又唤醒进程R,则Q等待R执行;......,如此,在管程内部可能会出现多个等待进程
在管程内需要设置一个进程等待队列,称为紧急等待队列,紧急等待队列的优先级高于入口等待队列的优先级。
HOARE管程——条件变量的实现
条件变量——在管程内部说明和使用的一种特殊类型的变量
var c:condition;
对于条件变量,可以执行wait和signal操作
wait(c):
如果紧急等待队列非空,则唤醒第一个等待者;否则释放管程的互斥权,执行此操作的进程进入c链末尾
signal(c):
如果c链为空,则相当于空操作,执行此操作的进程继续执行;否则唤醒第一个等待者,执行此操作的进程进入紧急等待队列末尾。
管程的应用:用管程实现生产者消费者、JAVA中的类似机制
管程的实现:管程实现的两个主要途径:直接构造->效率高
间接构造:用某种已经实现的同步机制去构造
例如:用信号量及PV操作构造管程
用管程解决生产者消费者问题
MESA管程
Hoare管程的一个缺点:两次额外的进程切换
解决:signal->notify
notify:当一个正在管程中的进程执行notify(x)时,它使得x条件队列得到通知,发信号的进程继续执行。
使用NOTIFY要注意的问题
notify的结果:位于条件队列头的进程在将来合适的时候且当处理器可用时恢复执行。
由于不能保证在它之前没有其他进程进入管程,因而这个进程必须重新检查条件:用while循环取代if语句
导致对条件变量至少多一次额外的检测(但不再有额外的进程切换),并且对等待进程在notify之后何时运行没有任何限制
改进NOTIFY
对notify的一个很有用的改进:
- 给每个条件原语关联一个监视计时器,不论是否被通知,一个等待时间超过的进程将被设为就绪态
- 当该进程被调度执行时,会再次检查相关条件,如果条件满足则继续执行
超时可以防止如下情况的发生:
- 当某些进程在产生相关条件信号之前失败时,等待该条件的进程就会被无限制地推迟执行而处于饥饿状态
引入BROADCAST
broadcast:使所有在该条件上等待的进程都被释放并进入就绪队列
当一个进程不知道有多少进程将被激活时,这种方式是非常方便的
例子:生产者/消费者问题中,假设insert和remove函数都适用于可变长度的字符块,此时,如果一个生产者往缓冲区中添加了一批字符,它不需要知道每个正在等待的消费者准备消耗多少字符,而仅仅执行一个broadcast,所有正在等待的进程都得到通知并再次尝试运行。
当一个进程难以准确判断将激活哪个进程时,也可以使用广播
HOARE管程与MESA管程的比较
Mesa管程优于Hoare管程之处在于Mesa管程错误比较少
在Mesa管程中,由于每个过程在收到信号后都重新检查管程变量,并且由于使用了while结构,一个进程不正确的broadcast广播或发信号notify,不会导致收到信号的程序出错。
收到信号的程序将检查相关的变量,如果期望的条件没有满足,它会重新继续等待。