互斥和同步-消费者/生产者 (管程+消息传递)
管程
由一个或多个过程、一个初始化序列和局部数据组成的软件模块,主要特点:
>1. 局部数据变量只能被**管程的过程**访问,任何外部过程都不能访问 >2. 一个进程通过调用**管程的一个过程**进入管程. >3. 只能有一个进程在管程中执行,调用管程的任何其他进程都被**阻塞**,以等待管程可用
管程的互斥机制:
管程的数据每次只能被一个进程访问
通过放入 共享数据结构 从而实现访问该资源的进程的互斥
管程的同步工具:
目的: 当调用管程的进程被阻塞时 需要释放该管程供其他进程进入,当条件满足且管程可用则 进程从阻塞点重新进入管程.
解决方法: 使用条件变量支持同步, 提供2个函数来操作条件变量
- cwait(c) : 进程被条件c阻塞,管程可被其他进程调用
- csignal(c) : 恢复因条件c而被阻塞的进程, 若有多个这样的进程,且选择其中的一个
管程的结构
- 入口: 等待进入管程的进程队列
- 管程等待区域: 条件等待队列 和 紧急队列
- 管程的数据区域: 局部数据 条件变量 过程(1,2,3,4….) 初始化代码
管程的工作流程
- 入口队列保证一次只能有一个进程可以进入, 试图进入管程的进程被阻塞加入等待管程可用的进程队列
- 当使用管程的进程执行cwait(c)把自己阻塞在条件c上,则加入等待条件改变重进进入管程的队列 (队列在管程内部)
管程解决有界缓冲区 生产者\消费者 问题
管程的2个条件变量:
- notfull :缓冲区至少有增加一个字符的空间时,notfull为真
- notempty : 缓冲区至少还有一个字符时, notemprt为真
伪代码
1 |
|
- 优点:
- 管程有自己的互斥机制,通过控制条件变量完成进程的同步就行
- 使用信号量的话 互斥 和 同步 都要自己实现
消息传递
实际功能由原语提供: 原语:进程间消息传递的最小操作集
>send(destination,message); > >receive(source,message);
- 进程执行
send
原语2种可能- 不被阻塞
- 发送的进程被阻塞 知道 消息被目标进程所接受
- 进程执行
receive
原语后的可能- 直接受到消息 进程继续执行
- 等待消息:
- 该进程被阻塞直到消息到达
- 进程继续执行,放弃消息接受
三种组合
- 阻塞
send
,阻塞receive
:都被阻塞,直到消息完成传递,使得进程紧密同步 - 无阻塞
send
,阻塞receive
: 发送进程继续执行,而接受进程被阻塞直到请求消息到达 - 无阻塞
send
,无阻塞receive
直接寻址
- 上面都是直接寻址通过
send
的destination
和receive
的source
参数 例如:目标进程标识号
间接寻址
- 消息不从发出者直接到达接受者, 而是发送到一个共享的数据结构,由临时保存消息的队列组成,通常称为信箱
- 常见关系:
- 1对 1 :专用通信链接
- 多对1 :常见客户-服务器交互. 服务器由一个进程给其他许多进程提供服务(消息服务?)**,此时信箱常被称为端口**
- 1 对 多 : 某进程广播一条消息
- 多 对 多:
利用 消息传递 解决有限缓冲区 生产者\消费者 问题
思路
通过 消息传递的间接寻址, 除了传递信号外还传递数据
生产者将产生的数据作为消息发到信箱
mayconsume
,只要该信箱还有一条消息,消费者就可以开始消费那么
mayconsume
就作为缓冲区,全局变量capacity
确定缓冲区大小,信箱
mayproduce
开始时填满空消息,且等于信箱的容量,每次生产使得mayproduce
中的消息减少mayconsume
中的消息增多
通过这2个信箱(消息队列),可以有多个生产者和消费者,
伪代码
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!