P、V操作经典问题

1.设有一台计算机,有两条I/O通道,分别接一台卡片输入机和一台打印机。卡片机把一叠卡片逐一输入到缓冲区B1中,加工处理后再搬到缓冲区B2中,并在打印机上打印。

【解】
(0)分析题意,画出草图:
在这里插入图片描述
(1)设定三个进程:
I进程:负责把卡片上的信息输入缓冲区B1
P进程:负责从缓冲区B1中取到信息并加工处理,送到缓冲区B2
C进程:负责从缓冲区B2中取到信息,在打印机上打印

(2)假设B1缓冲区大小是M个单元,B2缓冲区大小是N个单元。

(3)设定四个信号量:
B1FULL:B1缓冲区已经使用的单元数,初始化为0
B1EMPTY:B1缓冲区未使用的单元数,初始化为M
B2FULL:B2缓冲区已经使用的单元数,初始化为0
B2EMPTY:B2缓冲区未使用的单元数,初始化为N

(4)根据题设书写算法:

I进程:

repeat
	P(B1EMPTY)
	把卡片信息写入缓冲区B1
	V(B1FULL)
util false

P进程:

repeat
	P(B1FULL)
	P(B2EMPTY)
	从B1中取信息
	加工处理
	送到B2
	V(B1EMPTY)
	V(B2FULL)
until false

C进程:

repeat
	P(B2FULL)
	从B2取信息
	打印
	V(B2EMPTY)
util false

2.生产者-消费者问题(缓冲区大小是1)
在这里插入图片描述A进程:生产者生产产品,放入缓冲区
B进程:消费者从缓冲区取产品,消费掉

设定信号量full和empty,full表示缓冲区已经使用的空间,初始化为0,empty表示缓冲区尚未使用的空间,初始化为1

A进程:

repeat
	生产产品
	P(empty)
	放入缓冲区
	V(full)
util false

B进程:

repeat 
	P(full)
	从缓冲区取产品
	V(empty)
	消费掉产品
false

3.生产者-消费者问题(缓冲区大小是k)
在这里插入图片描述
A进程:生产进程
B进程:消费进程

设定信号量full和empty,full表示缓冲区已经使用的空间,初始化为0,empty表示缓冲区尚未使用的空间,初始化为k。设定信号量mutex,初始值为1,用来互斥。

A进程:

i = 0;
repeat 
	生产产品
	P(empty)
	P(mutex)
	往缓冲区的i位置放入产品
	i = (i+1)%k;
	V(mutex)
	V(full)
false

B进程:

j = 0;
repeat
	P(full)
	P(mutex)
	从缓冲区的j位置取产品
	j = (j+1)%k;
	V(mutex)
	V(empty)
	消费掉产品
false

笔者认为,既然i和j都初始化为0,两个进程对环形缓冲池这一资源不需要做互斥。上述的互斥代码可用去掉。

4.读者-写者问题
多个进程可用同时读文件,任意一个进程在写文件的时候其他进程就不得对文件进行写或读操作,有进程在读文件的时候不允许别的进程写文件。

设定两个进程A(读进程)和B(写进程)。
设定信号量mutex对临界区资源做互斥,初始值为1。
设定信号量readerCount表示读者数量,初始值是0。
设定信号量write表示可用做写操作的能力,初始值为1。

A:

repeat
	P(mutex)
	readerCount++;
	if(readerCount == 1){//第一个读者来的时候,看看有没有写者在写文件
		P(write)
			//如果write是1,表明没有写者在写文件,把write减1,使得写者不能写文件,
			//如果write<1,表明现在有写者在写文件,需要等待写者写完
	}
	V(mutex)
	读文件
	P(mutex)
	readerCount--;
	if(readerCount == 0){//如果读者数量为0,此时写者是可写的
		V(write)
	}
	V(mutex)
util false

B:

repeat
	P(write)
	写文件
	V(write)
util false

5.哲学家就餐问题
说的是一个桌子周围坐5个哲学家,每个哲学家左右都只有一个叉子,每个哲学家要想吃饭,就必须同时拿起两个叉子,怎么5个哲学家同时拿起一侧的叉子而发现另一侧没有叉子的尴尬局面(死锁)?

笔者参考了《操作系统–精髓与设计原理》(美)William Stallings著的解决方案,书中说的真有趣,一种方案是教会哲学家用一个叉子吃饭就OK了!!哈哈哈哈,另一种方案就是增加一个服务生,每次只允许4个哲学家同时就坐,下面就是这个算法啦:

规定:哲学家编号依次是0,1,2,3,4,第i个哲学家左侧叉子编号是i,右侧叉子编号是(i+1)%5

int[] fork = new int[]{1,1,1,1,1};//5个叉子都能用,初始化为1

void philosopher(int i){
	while(true){
		思考
		P(fork[i])
		P(fork[(i+1)%5])
		吃饭
		V(fork[(i+1)%5])
		V(fork[i])
	}
}

void main(){
	cobegin
		philosopher(0);
		philosopher(1);
		philosopher(2);
		philosopher(3);
		philosopher(4);
	coend
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值