OS操作系统PV操作常见类型及解法模板

PV操作

考研408常见类型整合

基本流程
  1. 有几类进程?——每一类对应一个函数
  2. 在函数内部,用中文描述做了什么事情。——只做一次(不加while),不断重复(加while)
  3. 每个动作之前,想想是否要P什么?——若写P则必V,想想什么时候V
  4. 所有pv写完之后在去定义信号量
  5. 检查多个p操作连续出现的情况,是否会产生死锁

tips:

  • 某信号量连续出现不会死锁(即中间无别的P)
  • 连续多个P导致的死锁,可尝试调整顺序
  • 注意隐含互斥条件(临界区需要互斥访问)
常见考点类型

实现前驱关系,生产者消费者,哲学家,读写者(读优先/写优先/公平),理发师,吸烟者等

模板与案例
实现前驱关系
// 主要就是同步问题
semaphore a1=a2=b1=b2=c=e=d=0;
S1(){
    ...;//工作
    V(a1);V(a2);
}
S2(){
    P(a1);
    ...;//工作
    V(b1);V(b2);
}
S3(){
    P(a2);
    ...;//工作
    V(c);
}
S4(){
    P(b1);
    ...;//工作
    V(d);
}
S5(){
    P(b2);
    ...;//工作
    V(e);
}
S6(){
    P(c);
    P(d);
    p(e);
    ...;//工作
}

究极无敌tips

送分题没啥好说的

生产者消费者
// 无标准模板,根据流程分析,直接手撕~
// 两个生产车间动作不一致,外加装配车间->3个函数
// 车间都是重复操作->while
// 货架就是临界区,注意互斥访问
// 写一个P立即思考它的V在哪
p1(){// 生产A
    while(1){
        生产A;
        P(empty1);
        P(mutex1);
        放F1;
        V(mutex1);
        V(full1);
    }
}
p2(){// 生产B
    while(1){
        生产B;
        P(empty2);
        P(mutex2);
        放F2;
        V(mutex2);
        V(full2);
    }
}
p3(){// 装配
    while(1){
        P(full1);
       	P(mutex1);
        拿A;
        V(mutex1);
        V(empty1);
        P(full2);
        P(mutex2);
        拿B;
        V(mutex2);
        V(empty2);
        组装;
    }
}
							//最后定义信号量,但在试卷上要在函数之前定义
semaphore mutex1,mutex2=1;	//实现对两个货架的互斥访问
semaphore full1=full2=0;	//货架上的产品数
semaphore empty1=empty2=10;	//货架上的空位

究极无敌tips

老老实实分析就完事了~

有的情况是一次性取很多个,务必保证取十个的动作一气呵成完成!

哲学家
//只有一类进程,但要占用多种资源
//1. 定义大锁->semaphore Lock=1;
//2. 资源数->int a=0;b=8;c=5;
process(){
    while(1){
       P(Lock);
        if(资源都够){
            所有资源都减少;
            取xx资源;
            V(Lock);
            break;
        }
        V(Lock);  
    }
    做事(比如吃饭);
    P(Lock);
    归还所有资源,int值增加;
    V(Lock);    
}

究极无敌tips

无脑套模板就完事了

Semaphore mutex=1;//对资源的互斥访问
int pot=N;
int sear=M;
Eat(){
    进食堂;
    while(1){
        p(mutex);
        if(pot>=4 && seat>=1){//资源足够
            pot=pot-4;
            seat=seat-1;
            v(mutex);//拿完资源解锁
            break;
        }
        v(mutex);//资源不够解锁
    }
    打菜吃饭;
    P(mutex);//一口气归还所有资源
    pot=pot+4;
    seat=seat+4;
    V(mutex);
    离开;
}
读写者
//读优先
int count=0;//读者数
semaphore mutex=1;//互斥访问count
semaphore Lock=1;//互斥使用资源
writer(){
    while(1){
        P(Lock);//互斥使用资源;
        V(Lock);
    }
}
reader(){
    while(1){
        P(mutex);
        if(cout==0){
            P(Lock);//当第一个读者来时,上锁,只允许读者们使用
        }
        count++;
        V(mutex);;
        P(mutex);
        count--;//读完了,读者-1
        if(count==0){
            V(Lock);//最后一个读者完事后,把锁打开,这样写者可以使用
        }
        V(mutex);
    }
}


//写优先
int readcount=0;//读者数
int writercount=0;//写者数
semaphore readmutex=1;//互斥访问readcount
semaphore writermutex=1;//互斥访问writercount
semaphore read=1;//给读者上锁
semaphore writer=1;//给写者上锁
writer(){
    while(1){
        P(writermutex);
        writecount++;
        if(writercount==1){
            P(read);//第一个读者对读者上锁,实现写优先
        }
        V(writermutex);
        P(writer);//每个读者写之前都要P(witer),保证写者之间的互斥,也能保证若有读者,写者会阻塞等待;
        V(writer);
        P(writermutex);
        writecount--;
        if(writercount==0){
            V(read);//最后一个写者写完后,对读者解锁
        }
        V(writermutex);
    }
}
reader(){
    while(1){
        P(read);//每个读者到达时先对read上锁
        P(readmutex);
        readcount++;
        if(readcount==1){
            P(writer);//第一个读者对write上锁,不让写者写
        }
        V(readmutex);
        V(read);//每个读者开始读之前先对read解锁;
        P(readmutex);
        readcount--;
        if(readcount==0){
            V(write);//最后一个读完的对write解锁,允许写者写
        }
        V(readmutex);
    }
}


//读写公平
int count=0;//读者数
semaphore mutex=1;//互斥访问count
semaphore Lock=1;//互斥使用资源
semaphore queue=1;//用于实现公平,可将其理解为一个队列,当资源不可访问时,都需要公平排队
writer(){
    while(1){
        P(queue);
        P(Lock);//互斥使用资源;
        V(Lock);
        V(queue);
    }
}
reader(){
    while(1){
        P(queue);
        P(mutex);
        if(cout==0){
            P(Lock);//当第一个读者来时,上锁,只允许读者们使用
        }
        count++;
        V(mutex);
        V(queue);;
        P(mutex);
        count--;//读完了,读者-1
        if(count==0){
            V(Lock);//最后一个读者完事后,把锁打开,这样写者可以使用
        }
        V(mutex);
    }
}
理发师
// 核心思路就是将其改造成生产者消费者问题

// 第一类:服务者可以睡觉休息,先取号再等号,无等位上限
int waiting=0;//等待服务的顾客数
semaphore mutex=1,customer=0,server=0;//互斥访问waiting|顾客资源|服务员资源
server_i(){//n个服务员进程
	while(1){
        P(customer);//消耗一个顾客资源,若无顾客则休息
        P(mutex);
        waiting--;//等待人数-1(相当于叫号)
        V(server);//释放一个服务员资源
        V(mutex);
        提供服务;
    }
}
customer(){
    P(mutex);
    waiting++;//等候顾客数+1(相当于取号)
    V(customer);//释放一个顾客资源
    V(mutex);
    P(server);//消耗一个服务资源
    被服务;
}


// 第二类:服务者不睡觉(忙等),先取号再等号,无等位上限
int waiting=0;//等待服务的顾客数
semaphore mutex=1,server=0;//互斥访问waiting|服务员资源
//这里不用定义顾客资源,因为参考第一类,若写了会造成阻塞(睡觉),不符合题意了
server_i(){
	while(1){
        P(mutex);
        if(waiting>0){
            waiting--;//等待人数-1(相当于叫号)
            V(server);//释放一个服务员资源
        	V(mutex);
        }else{
            V(mutex);
            continue;// 忙等
        }
        提供服务;
    }
}
customer(){
    P(mutex);
    waiting++;
    V(mutex);
    P(server);//消耗一个服务资源
    被服务;
}


// 第三类:服务者可以睡觉休息,有座位限制,若无则离开
int waiting=0;//等待服务的顾客数
int chair=m;//位子数
semaphore mutex=1,customer=0,server=0;//互斥访问waiting|顾客资源|服务员资源
server_i(){
	while(1){
        P(customer);//消耗一个顾客资源
        P(mutex);
        waiting--;//等待人数-1(相当于叫号)
        V(server);//释放一个服务员资源
        V(mutex);
        提供服务;
    }
}
customer(){
    P(mutex);
    if(waiting<chair){
        waiting++;
    	V(customer);//释放一个顾客资源
    	V(mutex);
    	P(server);//消耗一个服务资源
    	被服务;
    }else{
        离开;
        V(mutex);
    }
}

究极无敌tips

按照情况进行分类,此类具有一定区分度,但分出类别再使用模板,直接手撕~

// 分析类型(服务者可以睡觉,有座位限制)
int waiting=0;//等待服务顾客数
int char=n;//椅子数
semaphore mutex=1,customer=0,barber=0;
barber(){
    while(1){
        P(customer);//消耗一个顾客资源,没有顾客就阻塞(睡觉)
        P(mutex);
        waiting--;
        V(barber);//释放一个理发师资源(叫醒)
        V(mutex);
        剪发;
    }
}
customer(){
    P(mutex);
    if(waiting<chair){
        waiting++;
        V(customer);
        V(mutex);
        P(barber);
        被服务;
    }else{
        离开;
        V(mutex);
    }       
}
吸烟者
// 本质上就是生产者消费者问题(一生产多消费)
int num=0;// 用于存储随机数(用于实现轮流抽烟)
semaphore offer1=0;//定义信号量对应烟草和纸组合的资源
semaphore offer2=0;//定义信号量对应烟草和胶水组合的资源
semaphore offer3=0;//定义信号量对应纸和胶水组合的资源
process1(){
    while(1){
        num++;
        num=num%3;
        if(num==0){
            V(offer1);
        }else if(num==1){
            V(offer2);
        }else{
            V(offer3);
        }
        放对应的两种材料;
        P(finish);//没抽完之前出于阻塞状态,抽完后进行下一组分配
    }
}
process2(){
    while(1){
        P(offer1);
        拿所需材料抽烟;
        V(finish);
    }
}
process3(){
    while(1){
        P(offer2);
        拿所需材料抽烟;
        V(finish);
    }    
}
process4(){
    while(1){
        P(offer3);
        拿所需材料抽烟;
        V(finish);
    }   
}

模板后面对应的是例题,但是例题的图片被笔者弄丢了,望见谅,内容有误可指出~

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会不了一点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值