PV操作大题
利用信号量进行进程同步
- 信号量只有两种操作:赋初值和 PV 操作
- P 和 V 成对出现,有时可能距离较远
- 尽量先执行同步 P,后执行互斥 P
- 某些问题中,互斥问题存在,但是不需要单独设置互斥信号量解决(可能同步信号量已经解决了)
例题 1
问题描述:
假设一个系统有三个抽烟者进程和一个供应者进程。
每个抽烟者不停地卷烟并抽掉它,但要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。
三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。
供应者进程无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉已完成,此时供应者就会将另外两种材料放到桌上,如此重复(让三个抽烟者轮流地抽烟)。
步骤
分析有几个进程
- 抽烟者进程
- 供应者进程
分析每个进程需要的步骤
| 抽烟者进程 | 吸烟者进程 |
|---|---|
| 卷烟 | 供应原材料 |
| 吸烟 |
分析等待和停止的契机
| 抽烟者进程 | 吸烟者进程 |
|---|---|
| 等待材料 | 等待信号 |
| 卷烟 | 供应原材料 |
| 吸烟 | 解除材料等待 |
| 解除信号等待 |
具体化吸烟者进程和材料
把三种材料分别简化为 A,B,C
c
void 抽烟者1() {
while(1) {
P(A);
卷烟;
吸烟;
V(producer);
}
}c
void 抽烟者2() {
while(1) {
P(B);
卷烟;
吸烟;
V(producer);
}
}c
void 抽烟者3() {
while(1) {
P(C);
卷烟;
吸烟;
V(producer);
}
}具体化供应者
c
void 供应者() {
while(1) {
P(producer);
if (i % 3 == 0) {
供应 A 吸烟者;
V(A);
}
if (i % 3 == 1) {
供应 B 吸烟者;
V(B);
}
if (i % 3 == 2) {
供应 C 吸烟者;
V(C);
}
i++;
}
}信号量
c
Semphore producer = 1, A = 0, B = 0, C = 0;
int i = 0;对每个 PV 操作添加注释
例题 2
三个进程 P1,P2,P3 互斥使用一个包含N(N>0)个单元的缓冲区。
P1每次用produce()生成一个正整数并用put()送入缓冲区某一空单元;
P2每次用getodd()从该缓冲区中取出一个奇数并用countodd()统计奇数个数;
P3每次用geteven()从该缓冲区中取出一个偶数并用counteven()统计偶数个数。
请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义的信号量的含义(要求用伪代码描述)。
解法
列出空缓冲区
| P1 | P2 | P3 |
|---|---|---|
| produce() | getodd() | geteven() |
| put() | countodd() | counteven() |
写出等待
先同步,后互斥
| P1 | P2 | P3 |
|---|---|---|
| 等待奇数 | 等待偶数 | |
| 访问缓冲区 | 访问缓冲区 | |
| produce() | getodd() | geteven() |
| 等待空缓冲区 | 离开临界区 | 离开临界区 |
| 进入临界区 | 解除缓冲区等待 | 解除缓冲区等待 |
| put() | countodd() | counteven() |
| 离开临界区 | ||
| 若是奇数,则解除奇数等待 | ||
| 若是偶数,则解除偶数等待 |
写出代码
c
void P1() {
while(1) {
produce();
P(empty); // 等待空缓冲区
P(mutex); // 进入临界区
put();
V(mutex); // 离开临界区
if (x % 2 == 0)
V(even); // 增加偶数
else
V(odd); // 增加奇数
}
}c
void P2() {
while(1) {
P(odd); // 等待奇数
P(mutex); // 访问缓冲区
getodd();
V(mutex); // 离开临界区
V(empty); // 释放一个缓冲区单元
countodd();
}c
void P3() {
while(1) {
P(even); // 等待偶数
P(mutex); // 访问缓冲区
geteven();
V(mutex); // 离开临界区
V(empty); // 释放一个缓冲区单元
countodd();
}理发师问题
分析
| 理发师 | 顾客 |
|---|---|
| 等待顾客 | 解除理发师等待顾客 |
| 等待理发师空闲 | |
| 提供服务 | 接收服务 |
| 理发师空闲 |
tricking 小本子记录问题
对于一个小本子,来的人画一个线,走的时候擦除。
则:
进入时:
c
P(mutex);
if (waiting...满足某某) {
waiting++;
V(mutex);
}
else {
V(mutex);
离开;
}离开时:
c
P(mutex);
waiting--;
V(mutex);