记录PV操作学习过程中的一些习题相关代码
1、读者/写者问题
两组并发进程:读者/写者,共享一个文件F:
- 多个读者可以同读【允许同读】
- 只允许一个写者写文件【同写互斥】
- 写者写时不能被读者读【读写互斥】
- 写者写之前应该让已有读者写者都退出
读者优先
用wmutex来限制写者,使读者优先
semaphore rmutex=1,wmutex=1;
int readcount=1;
cobegin
process Reader_i(){
while(true){
P(rmutex);
if(readcount==0)P(wmutex)
readcount++;
V(rmutex);
{读文件}
P(rmutex);
readcount--;
if(readcount==0)V(wmutex);
V(rmutex);
}
}
process Writer_i(){
while(true){
P(wmutex);
{写文件}
V(wmutex);
}
}
coend
写者优先
用rmutex来限制读者,使写者优先
semaphore rmutex=1,wmutex=1;
semaphore x=1,y=1,z=1;
int readcount=0,writecount=0;
cobegin
process Reader_i(){
while(true){
P(z);
P(rmutex);
P(x);
if(readcount==0)P(wmutex);
readcount++;
V(x);
V(rmutex);
V(z);
{读文件}
P(x);
readcount--;
if(readcount==0)V(wmutex);
V(x);
}
}
process Writer_i(){
while(true){
P(y);
if(writecount==0)P(rmutex);
writecount++;
V(y);
P(wmutex);
{写文件}
V(wmutex);
P(y);
writecount--;
if(writecount==0)V(rmutex);
V(y);
}
}
coend
读写公平
用公共信号量S来使读写公平
semaphore rmutex=1,wmutex=1,s=1;
int readcount=0;
cobegin
process Reader_i(){
while(true){
P(s);
P(rmutex);
if(readcount==0)P(wmutex);
readcount++;
V(rmutex);
{读文件}
P(rmutex);
readcount--;
if(readcount==0)V(wmutex);
V(rmutex);
V(s);
}
}
process Writer_i(){
while(true){
P(s);
P(wmutex);
{写文件}
V(wmutex);
V(s);
}
}
coend
2、睡眠的理发师问题
一位理发师、一把理发椅、n把等候区
- 如果没有顾客,理发师就休眠
- 顾客到来需要唤醒理发师
- 如果理发师正在理发时来了顾客,就在等待区等待,等待区满则直接离开
- 不是互斥型问题,而是协作型问题!
【用customers来限制理发师进程,用barbers来限制顾客进程,协作同步】
semaphore customers=0,barbers=0,mutex=1;
int waiting=0,chairs=n;
cobegin
process Barber(){ //理发师需要一直提供服务,所以需要无限循环
while(true){
P(customers); //是否有顾客,若无则进入休眠(信号量<0)
P(mutex); //有顾客,进入操作处理临界区
waiting--; //让一个等待的顾客过来理发
V(barbers); //理发师被唤醒了,释放一个可理发资源
V(mutex); //退出操作处理临界区,下面正式开始理发
{理发师理发}
}
}
process Customer(){ //顾客只接受一次服务,所以不需要无限循环
P(mutex); //进入操作处理临界区
if(waiter<chair){ //判断等待区是否还有位置
waiting++; //等待人数
V(customers); //顾客资源数++,并唤醒休眠中的理发师
V(mutex); //退出操作处理临界区
P(barbers); //请求一个理发师资源,如果barbers<0,则先到等待区等待一下
{被理发师理发}
}
else{
V(mutex); //等待区满,顾客直接离开
}
}
coend
3、农夫猎人问题/苹果橘子问题
一个笼子,只能放一个老虎或羊,动物园或饭店从中取对应的动物;
一个盘子,只能放入一个苹果或橘子,爸爸妈妈分别取苹果和橘子;
【两组生产者和消费者共同使用一个缓冲区】
semaphore sput=1,sget[2]={0,0};
cobegin
process Product_i(int i){
while(true){
P(sput);
{放产物}
V(sget[i]);
}
}
process Consumer_i(int i){
while(true){
P(sget[i]);
{取产物}
V(sput);
}
}
coend
4、银行业务问题
- n个储蓄员,足够多的顾客,足够多的等待区
- 顾客到来先取号,然后等待叫号
- 每当有储蓄员空闲下来就叫下一个号
semaphore customer=0,server=n.mutex=1;
cobegin
process Customer(){ //每个顾客只来一次,所以顾客进程不需要无线循环
P(mutex);
{取号并在等待区坐下}
V(mutex);
V(customer);
P(sever);
{接受服务};
}
process Server_i(){ //储蓄员需要不断提供服务,所以需要无线循环
while(true){
P(customer);
P(mutex);
{向顾客叫号,被叫到顾客离开等待区}
V(mutex)
{为顾客提供服务}
V(server);
}
}
coend
5、缓冲区管理
- n个输入进程Pi将字符逐个输入容量为80的缓冲区中
- 缓冲区满后,输出进程Q一次性取走80个字符
semaphore empty=80,full=0,mutex=1;
char buffer[80];
int count=0,inptr=0;
cobegin
process P_i(){
while(true){
P(empty);
p(mutex);
{写入字符到buffer[inptr]}
count++;
inptr=(inptr+1)%80;
if(count==80){
count=0;
V(mutex);
V(full);
}
else V(mutex);
}
}
process Q(){
while(true){
P(full);
P(mutex);
{读取80个字符}
V(mutex);
for(int i=0;i<80;i++){
V(empty);
}
}
}
coend
6、售票问题
汽车司机和售票员之间协同工作:
- 售票员关好门并通知司机开车,然后售票员售票【关门通知司机】
- 司机停车后通知售票员才能开门上下客【停车通知售票员】
- 一名司机,两名售票员,从始发站开始
semaphore run[2]={0,0},stop[2]={0,0};
cobegin
process Driver(){
while(true){
P(run[0]);
P(run[1]);
{开车}
{停车}
V(stop)
}
}
process Saler_i(int i){
while(true){
{上客}
{关车门}
V(run[i]);
{售票}
P(stop[i]);
{开车门}
{下客}
}
}
coend
7、吸烟者问题
三个吸烟者+一个供应者,每个吸烟者有一种特别的材料,每次供应者会放两种材料出来,如果跟自己的都不一样,就轮到对应的吸烟者吸烟了
- 供应者随机放两种材料
- 吸烟完毕后唤醒供应者
semaphore producter=1,smoker[3]={0,0,0};
cobegin
process Product(){
while(true){
P(producter);
{随机放两种材料,假设放的材料对应的可吸烟者是i}
V(smoker[i]);
}
}
process Smoker_i(int i){
while(true){
P(smoker[i]);
{吸烟}
V(producter);
}
}
8、独木桥问题
有一根独木桥,来自东西两个方向的汽车要通过桥
一边全过完再换边【不公平】
只有一方的车全部过完之后才允许另一方的车过桥,不公平
semaphore wait=1,mutexleft=1,mutexright=1; //使用wait来饿死另一边
int countleft=0,countright=0;
cobegin
process CarLeft(){ //每辆车都调用CarLeft函数即可,所以不需要无限循环
P(mutexleft);
if(countleft==0)P(wait);
countleft++;
V(mutexleft);
{过桥}
P(mutexleft);
countleft--;
if(countleft==0)V(wait);
V(mutexleft);
}
process CarRight(){ //每辆车都调用CarRight函数即可,所以不需要无限循环
P(mutexright);
if(countright==0)P(wait);
countright++;
V(mutexright);
{过桥}
P(mutexright);
countright--;
if(countright==0)V(wait);
V(mutexright);
}
coend
限制最大同时通过车辆数【不公平】
在上述不公平情况下,限制同时通过桥的车辆数量为k
semaphore wait=1,mutexleft=1,mutexright=1,maxpass=k;
int countleft=0,countright=0;
cobegin
process CarLeft(){ //每辆车都调用CarLeft函数即可,所以不需要无限循环
P(mutexleft);
if(countleft==0)P(wait);
countleft++;
V(mutexleft);
P(maxpass); //对同时最大通过数量加以限制
{过桥}
V(maxpass);
P(mutexleft);
countleft--;
if(countleft==0)V(wait);
V(mutexleft);
}
process CarRight(){ //每辆车都调用CarRight函数即可,所以不需要无限循环
P(mutexright);
if(countright==0)P(wait);
countright++;
V(mutexright);
P(maxpass); //对同时最大通过数量加以限制
{过桥}
V(maxpass);
P(mutexright);
countright--;
if(countright==0)V(wait);
V(mutexright);
}
coend
以组单位交替运行【公平】
在第一种的基础上,要求保证以k辆为一组为单位交替运行
semaphore wait=1,mutexleft=1,mutexright=1; //使用wait来饿死另一边
int countleftup=0,countleftdownp=0,countrightup=0,countrightdown=0;
cobegin
process CarLeft(){ //每辆车都调用CarLeft函数即可,所以不需要无限循环
P(mutexleft);
if(countleftup==0)P(wait);
countleftup++;
V(mutexleft);
{过桥}
P(mutexleft);
countleftup--; countleftdown--;
if(countleftup==0 && countleftdown==k){
countleftdown=0;
V(wait);
}
V(mutexleft);
}
process CarRight(){ //每辆车都调用CarRight函数即可,所以不需要无限循环
P(mutexright);
if(countrightup==0)P(wait);
countrightup++;
V(mutexright);
{过桥}
P(mutexright);
countrightup--; countrightdown++;
if(countrightup==0 && countrightdown==k){
countrightdown=0;
V(wait);
}
V(mutexright);
}
coend
类读写公平【公平】
当另一方提出过桥时,应当能阻止当前方的后继车辆,保证公平
semaphore stop=1,wait=1,mutexleft=1,mutexright=1; //增加stop全局信号量来实现公平
int countleft=0,countright=0;
cobegin
process CarLeft(){ //每辆车都调用CarLeft函数即可,所以不需要无限循环
P(stop);
P(mutexleft);
if(countleft==0)P(wait);
countleft++;
V(mutexleft);
{过桥}
P(mutexleft);
countleft--;
if(countleft==0)V(wait);
V(mutexleft);
V(stop);
}
process CarRight(){ //每辆车都调用CarRight函数即可,所以不需要无限循环
P(stop);
P(mutexright);
if(countright==0)P(wait);
countright++;
V(mutexright);
{过桥}
P(mutexright);
countright--;
if(countright==0)V(wait);
V(mutexright);
V(stop);
}
coend