2.2进程间通信
如何保证多进程程序运行的结果是确定的?
可能的方法
关中断/锁变量
- 操作不是原子的,则还会是出现问题。
- 问题的根源还在于操作的可以被打断
- 故锁变量仍然存在竞争条件
严格交替法
- 确保两个进程严格轮流进入临界区
避免同时进入临界区
忙等待
测试是否可以进入临界区(进程自身的一段代码,这段代码有访问共享变量的可能),不允许则该进程忙等待直至许可为止
Peterson互斥解法
- Enter_region(int process_id);
- 临界区
- leaver_region();
while(turn==process&&interested[other]==TRUE);/这个地方的意思是while的空转,注意这个分号/
busy loop
TSL解法
- 测试并上锁(保证原子性)
- 执行TSL指令的CPU将锁住内存总线以禁止其他CPU在本指令结束之前访问内存。
无论是硬件解法还是软件解法都实现了busy loop
- 若等待时间过长可能会造成CPU时间的浪费。
非忙等待:睡眠等待(睡眠和唤醒)
忙等待的问题:
- 优先级的翻转问题:对于优先级有高低的两个进程,优先级高的进程会不停的在忙等待优先级低的进程,但优先级低的进程因为较低的优先级不能被调度,所以会形成这种困境。
睡眠等待
- 无法进入临界区时将阻塞,而不是忙等待
- 最简单的是睡眠(SLEEP)和唤醒(Wake up)
含竞争条件的生产者和消费者问题(if语句执行时的被打断)
- 由于对count的访问未加限制,会导致生产者添满整个缓冲区。
- 增加唤醒等待位。
信号量与原语
原语
- 定义:由若干条指令构成的“原子操作”过程。c.f.原子操作
- 并不是所有系统调用都是原语
信号量和P、V原语
- 一个信号量的值可以为0,表示没有积累下来的唤醒操作。
- “二进制信号量”
Down 和 up
down操作(检查信号量值是否大于0)
检查信号量的值是否大于0.
组成步骤:检查数值/改变数值
都作为单一的不可分割的操作完成。c.f.if的可分割。
up操作(递增信号量的值)
- 如果有一个或多个进程在该信号量上睡眠,则由系统选择其中(random)一个并允许其完成 它的down操作
- 如果有一个进程在其上睡眠的信号量执行…
- 进程执行up操作时不会被阻塞。
利用信号量解决生产者-消费者问题【考试】
1 |
|
互斥
利用信号量实现互斥
P(mutex);【加锁】
/Code section/
V(mutex);【解锁】
/remainder Code section/
定义锁变量,加锁/解锁
注意pV 需要成对使用和次序。
管程(monitor)
- 为了保证分布式程序的100%OK。
- 排除掉系统的语义bug
- 基本思想:将信号量和操作原语封装到一个对象内部。
- 特殊的模块/软件包
主要特性
- 模块化
- 信息封装(半透明)的。
管程的实现要素
- 管程的共享变量在管程外部不可见
- 管程互斥进入
- 管程->管理资源,因而在管程中应当设有 进程等待队列以及相应的等待及唤醒操作
条件变量
当进入管程的进程因资源被占用等原因不能继续运行时使其等待。
- 每个表示一种等待原因,相当于每个原因对应一个队列。
消息传递
进程间通讯
- SEND
- RECEIVE
消息传递系统要点:
- 防止消息丢失:ACK
- 区分新老消息:编号
- 消息系统解决进程命名的问题:以明确在SEND和RECEIVE调用中所指定的进程。
MPI例子
- MPI:消息传递机制的一种。
- 通过MPI run在两台机器上运行。
1 | /*从A机器上的P1给B机器上的P2发送消息*/ |