Skip to content

PV操作大题

【十分钟学会pv操作(视频里讲了三个题)】

利用信号量进行进程同步

  1. 信号量只有两种操作:赋初值和 PV 操作
  2. P 和 V 成对出现,有时可能距离较远
  3. 尽量先执行同步 P,后执行互斥 P
  4. 某些问题中,互斥问题存在,但是不需要单独设置互斥信号量解决(可能同步信号量已经解决了)

例题 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()统计偶数个数。

请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义的信号量的含义(要求用伪代码描述)。

解法

列出空缓冲区

P1P2P3
produce()getodd()geteven()
put()countodd()counteven()

写出等待

先同步,后互斥

P1P2P3
等待奇数等待偶数
访问缓冲区访问缓冲区
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);