PV操作
- 观察者和报告者是两个并发执行的进程。
观察者不断观察并对通过的卡车计数;
报告者不停地将观察者的计数打印,并归零。
请用P、V原语进行正确描述。
int count=0;
Semaphore mutex=1;
Observer: Reporter: Main():
while(true): while(true): parbegin
P(mutex): P(mutex) Observer();
打印count; Rporter();
count++; count=0; parend
V(mutex); V(mutex)
-
图书馆问题:图书馆有N个座位,一张登记表,要求:
读者进入时需先登记,取得座位号;
出来时注销
用P、V原语描述读者的使用过程。Semaphore count=N; Semaphore mutex=1; Main(): parbegin: In(); 阅读; Out(); parend In(): while(true): P(count): P(mutex): 登记; V(mutex); Out(): while(true): P(mutex): 注销 V(mutex); V(count);
-
公交车场景
Semophore door=0//是否允许售票员开门
Semophore car=0//是否允许司机启动汽车
Main():
Driver();
Conductor();
Driver():
while:
P(car):
启动;
运行;
停车;
V(door);
Conductor():
while(true):
关车门;
V(car);
售票;
P(door):
开车门;
-
生产者与消费者问题:生产者:满则等待,空则填充
消费者:空则等待,有则获取
不允许同时进入缓冲区先拿资源再拿锁
- 无限缓冲
semaphore num=0;
semaphore mutex=1;
Producer:
while(true):
生产;
P(mutex):
填充buffer;
V(mutex);
V(num);
Consumer:
while(true):
P(num):
P(mutex);
消费buffer;
V(mutex);
消费;
- 有限缓冲
semaphore full=0;//满 缓冲区数量
semaphore empty=N;//空 缓冲区数量
semaphore mutex=1;//互斥访问缓冲区
Producer():
P(empty);
P(mutex):
填充buffer;
V(mutex);
V(full);
Consumer():
P(full):
P(mutex):
消费buffer;
V(mutex);
V(empty);
- 管程解决
monitor PC{//管程本身实现了互斥,无限互斥信号量
int in=0,out=0,count=0;
item buffer[n];
condition empty,full;//需要资源信号量,条件变量
put(item){
if(count>=n)
full.wait();
buffer[in]=item;
in=(in+1)%n;
count++;
if(empty.queue)
empty.signal();
}
get(){
if(count<=0){
empty.wait();
}
item=buffer[out];
out=(out+1)%n;
count--;
if(full.queue){
full.signal();
}
return item;
}
}
- 与进程的执行顺序有关的问题
资源信号量P、V操作分布在不同进程
互斥信号量P、V操作出现在同一进程
semaphore mutex1=1,mutex2=1;
semaphore empty1=1,empty2=1;//分别表示缓冲区1及缓冲区2是否为空,初值为1。
semaphore full1=0,full2=0;//分别表示缓冲区1及缓冲区2是否有记录可供处理,初值为0
PA(){
while(1){
从磁盘读一个记录;
P(empty1):
P(mutex1):
将记录存入缓冲区1;
V(mutex1);
V(full1);
}
}
PB(){
while(1){
P(full1):
P(mutex1):
P(empty2):
P(mutex2):
从缓冲区1中取出记录放去缓冲区2;
V(mutex1);
V(empty1);
V(mutex2);
V(full2);
}
}
PC(){
while(1){
P(full2):
P(mutex2):
从缓冲区2读打印;
V(mutex2);
V(empty2);
}
}
Main(){
parbegin()
PA();
PB();
PC();
parend;
}
- 读者/写者问题:Readers-Writers Problem
三个角色
一个共享的数据区;
Reader: 只读取这个数据区的进程;
Write: 只往数据区中写数据的进程;
三个条件
多个Reader可同时读数据区;
一次只有一个Writer可以往数据区写;
数据区不允许同时读写。
int readcount=0;
semaphore mrc=1,r=1,w=1;
Reader{
读书;
P(mrc):
readcount--;
if(readcount==0):
V(w);
V(mrc);
}
Writer{
P(r):
P(w):
写;
V(w);
V(r);
}
- 哲学家就餐问题
- 最多允许4个哲学家同时进食
//为资源(餐叉)分配一个偏序关系,所有资源都按此顺序获取,按照相反顺序释放
//给哲学课编号,奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之
semaphore fork[5]={1,1,1,1,1};
int i;
void philosopher(int i){
while(i){
think();
if(i%2==0){
P(fork(i));
P(fork[(i+1)%5]);
}else{
P(fork[(i+1)%5]);
P(fork[i]);
}
eat();
V(fork[(i+1)%5]);
V(fork[i]);
}
}
-
哲学家升级版本:
餐叉编号为1至5,每个哲学家总是先拿起左右两边编号较低的餐叉,再拿编号较高的。用完餐叉后,他总是先放下编号较高的餐叉,再放下编号较低的。
#define N 5
#define LEFT (i-1+N)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
int state[N]={0,0,0,0,0};
semaphore mutex=1;
semaphore s[N]={0,0,0,0,0};
take_forks(int i):{
P(mutex):
state[i]=HUNGRY;
test[i];
V(mutex);
P(s[i]);
}
put_forks(i){
P(mutex):
state[i]=THINKING;
test(LEFT);
test(RIGHT);
test(RIGHT);
V(mutex);
}
test(i){
//如果只有一边的刀叉就绪,直接退出 if,只有两边就绪才会进入 if。从效果上看,就是 test(i-1) 可能什么效果都没有,test(i+1) 会设置。
if(state[i]==HUNGRY&&state[LEFT]!=EATING&&state[RIGHT]!=EATING){
state[i]=EATING;
V(s[i]);
}
}
//管程解法
#define N 5
#define THINKING 0
#define HUNGRY 1
#define EATING 2
monitor philosopherMal{
int state[N]={0,0,0,0,0};
condition self[N]={0,0,0,0,0};
void test(int i){
if(state[i]==HUNGRY)&&(state[(i+4)%5]!=EATING)&&(state[i+1]%5!=EATING){
state[i]=EATING;
self[i].signal;
}
void take_forks(int i){
state[i]=HUNGRY;
test(i);
if(state[i]!=EATING){
self[i].wait();
}
}
void put_forks(int i){
state[i]=HUNGRY;
test((i+4)%N);
test((i+1)%N);
}
}