1)管程monitor
信号量机制的不足:程序编写困难、易出错
解决办法:在程序设计语言中引入管程成分;一种高级同步机制
a.定义:是一种特殊的模块,由关于共享资源的数据结构及在其上操作的一组过程组成
进程与管程的关系:进程只能通过调用管程中的过程来间接地访问管程中的数据结构
管程要保证:互斥:管程是互斥进入地——为了保证管程中数据结构的数据完整性;由编译器负责保证
同步:管程中设置条件变量及等待/唤醒操作以解决同步问题
可以让一个进程或线程在条件变量上等待(此时,应先释放管程的使用权),也可以通过发送信号将等待在条件变量上的进程或线程唤醒
条件变量:为进程或其他进程通信或同步而引入的(wait/signal或wait/notify或wait/broadcast
b.应用管程遇到的问题:当一个进入管程的进程执行等待操作时,它应当释放管程的互斥权,当后面进入管程的进程执行唤
醒操作时(例如P唤醒Q),管程中便存在两个同时处于活动状态的进程
三种处理方法:Hoare:P等待Q执行;(先进入管程的进程运行)
MESA:Q等待P继续执行
Hansen(并发pascal):规定唤醒操作作为管程中最后一个可执行的操作
c.HOARE管程:
因为管程是互斥进入的,所以当一个进程试图进入一个已被占用的管程是,应当在管程入口处等待(为此,
管程入口处设置一个进程等待队列,称作入口等待队列)
如果进程P唤醒进程Q,则P等待Q执行;如果进程Q执行中又唤醒进程R,则Q等待R执行;……如此管程内部可能会
出现多个等待进程(在管程内设置一个进程等待队列,称为紧急等待队列,紧急等待队列的优先级高于入口等待队列的优先级)
HOARE管程——条件变量的实现
条件变量——在管程内部说明和使用的一种特殊类型的变量
var c:condition; //对于条件变量,可执行wait和signal操作
wait(c):如果紧急等待队列非空,则唤醒第一个等待者;否则释放管程的互斥权,执行此操作的进程进入c链末尾
signal(c):如果c链为空,则相当于空操作,执行此操作的进程继续执行,否则唤醒第一个等待者,执行此操作的进程进入紧急等待队列的末尾
管程的应用
管程实现的两个主要途径:
直接构造——》效率高
间接构造——》用某种已经实现的同步机制去构造
用管程解决生产者消费者问题
procedure producer;
begin
while true do
begin
item = produce_item;
ProducerConsumer.insert(item)
end
end;
procedure consumer;
begin
while true do
begin
item = ProducerConsumer.remove()
consume_item(item);
end
end;
monitor ProducerConsumer
condition full,empty;
integer count;
procedure insert(item:integer); //向缓冲区放数据
begin
if count == N then wait(full); //缓冲区满了
insert_item(item); count ++;
if count == 1 then signal(empty);//当缓冲区从空状态到有一个,唤醒消费者
end;
function remove:integer;
begin
if count == 0 then wait(empty);
remove = remove_item;count --;
if count = N - 1 then signal(full);
end;
count:=0;
end monitor;
d.MESA管程
Hoare管程的一个缺点:两次额外的进程切换(P进程唤醒了Q,Q进程执行,引起一次进程的切换,Q进程执行完了,再把P进程调度上CPU)
解决:
signal——》notify
notify:当一个正在管程中执行的进程执行notify(x)时,它使得x条件队列得到通知,发信号的进程继续执行
notify的结果:位于条件队列头的进程在将来合适的时候且当处理器可用时恢复执行
由于不能保证在它之前没有其他进程进入管程,因而这个进程必须重新检查条件——》用while循环取代if语句
导致对条件变量至少多一次额外的监测,并且对于等待进程在notify之后何时运行没有任何限制
改进notify:给每个条件原语关联一个监视计时器,不论是否被通知,一个等待时间超时的进程将被设为就绪态
当该进程被调度执行时,会再次检查相关条件,如果条件满足则继续执行
超时可以防止如下情况发生:当某些进程在产生相关条件的信号之前失败时,等待该条件的进程就会被无限制地推迟执行而处于饥饿状态
broadcast:使所有在该条件上等待的进程都被释放并进入就绪队列
在这种情况下使用:
当一个进程不知道有多少进程将被激活时,这种方式是非常方便的
当一个进程难以准确判定将激活哪个进程时
2)PTHREAD中同步机制
pthread_cond_wait的执行分解为三个主要动作:解锁、等待(当收到一个解除等待的信号马上需要做的动作是)、上锁
3)进程间通信Inter-Process Communication
信号量、管程只能传递简单的信息,管程不适于多处理器情况,所有还需要通信机制
进程通信机制——消息传递 send&receive原语
适用于分布式系统、基于共享内存的多处理机系统、单处理机系统,可以解决进程间的同步问题、通信问题
基本的通信方式:消息传递、共享内存、管道、套接字、远程过程调用
a.消息传递
消息缓冲区结构:消息头(消息类型、接受进程ID、放松进程ID、消息长度、控制信息),消息体(消息内容)
b.共享内存(程序员需要解决互斥问题)
c.管道通信方式PIPE
利用一个缓冲传输介质——内存或文件连接两个相互通信的进程
字符流方式写入读出
先进先出顺序
管道通信机制必须提供的协调能力:互斥、同步、判断对方进程是否存在
4)典型操作系统的IPC机制
a.UNIX: 管道、消息队列、共享内存、信号量、信号、套接字
b.Windows:同步对象:互斥对象、事件对象、信号量对象、临界区对象、互锁变量
套接字、文件映射、管道、命名管道、邮件槽、剪贴板、动态数据交换、对象连接与嵌入、动态链接库、远程过程调用
c.Linu:管道、消息队列、共享内存、信号量、信号、套接字
内核同步机制:原子操作、自旋锁、读写锁、信号量、屏障、BKL
原子操作:常用于实现资源的引用计数
屏障:一种同步机制(又称栅栏,关卡)
用于对一组线程进行协调
应用场景:一组线程协同完成一项任务,需要所有线程都到大一个汇合点后再一起向前推前例如(矩阵运算)