操作系统---PV大题

信号量代表某种资源

信号量mutex表示进入临界区的名额

同步信号量,初始为0  先V,S的值+1,再P时,是能申请到资源的,是可以执行的

V -->S+1  P -->S-1

一、生产者消费者问题(考的最多,进程与进程之间是“生产资源-消费资源”的关系)

1.解题思路

1.确定函数的个数:梳理题目中有几个进程,一个进程对应一个函数(根据动作是否一致区分是否为统一进程)

2.确定函数的动作:

①动作是什么:在函数内部,用中文描述动作

②动作的次数:只做一次(不加while)还是重复进行(while循环)

3.确定函数是否在每个动作之前需要进行P操作:如果需要进行P操作,则一定有与之对应的V操作;需要思考这个V操作应该被放在哪进行

消耗资源型的P操作:题目一般会显性给出,例如每次动作需要消耗一个缓冲区空间(P操作减少缓冲区空间,V操作增加缓冲区空间,缓冲区无空间时无法进行动作)

互斥型的P操作:需要注意隐含的互斥关系,例如缓冲区的互斥访问

4.确定信号量的个数:所有PV操作定义完成后,再确定信号量的个数

5.检查是否发生死锁:连续进行多个P操作的地方是否会发生死锁(只有一个P操作不会发生死锁)

①某信号量的PV连续出现(中间没有夹杂别的P操作),则不会发生死锁:不发生请求和保持

②连续多个P导致的死锁可尝试调整P顺序解决

  1. 生产者 - 消费者   生产产品--消耗产品

  1. 确定函数的个数(3):生产车间A和生产车间B虽然都是生产车间,但是它们俩执行的动作不一致,故不是同一个进程,即生产车间A和生产车间B需要对应不同的函数;

进程 = 生产车间A(P1) + 生产车间B(P2) + 装配车间(C)

2.确定函数的动作:

①动作是什么:

P1和P2分别生产A、B两种零件,并将分别把它们送到货架F1、F2上

C从货架上分别取出A、B后,组装成A + B

②动作的次数:P1、P2和C都是不断重复 → while

3.确定函数是否在每个动作之前需要进行P操作

①P1生产A零件之前不需要消耗资源

P1将A放到F1前需要消耗1个F1货架(A缓冲区)的剩余容量 → C从F1上取A后会释放1个F1货架的剩余容量

②P2生产B零件之前不需要消耗资源

P2将B放到F2前需要消耗1个F2货架(B缓冲区)的剩余容量 → C从F2上取B后会释放1个F2货架的剩余容量

③C从F1取A前需要消耗1个F1货架上的A产品 → P1把A放到F1后释放1个F1货架上的A产品

C从F2取B前需要消耗1个F2货架上的B产品 → P2把B放到F2后释放1个F2货架上的B产品

C组装成A+B前不需要消耗资源

④P1和C对F1的访问是互斥的(mutex1);P2和C对F2的访问是互斥的(mutex2)

4.确定信号量的个数:F1 = F2 = 10,full1 = full2 = 0,mutex1 = mutex2 = 1

5.检查是否发生死锁:先P同步信号量(F1、F2、full1、full2),再P互斥信号量(mutex1、mutex2)

1.确定函数的个数(2):老和尚喝水,小和尚取水

2.确定函数的动作:

①动作是什么:

老和尚从缸中打水、喝水

小和尚从井中打水、放水

②动作的次数:不断进行 → while

3.确定函数是否在每个动作之前需要进行P操作:

①老和尚打水前消耗1个桶 → 老和尚喝水后增加1个桶

老和尚喝水前消耗1个水缸里的水 → 小和尚打水后增加1个水缸里的水

②小和尚打水前消耗1个桶 → 小和尚放水后增加1个桶

小和尚打水前消耗1个水缸的剩余容量 → 老和尚喝水后增加1个水缸的剩余容量

③小和尚之间对井的访问是互斥的(mutex1);老和尚间和小和尚间、老和尚和小和尚对水缸的访问是互斥的(mutex2)

4.确定信号量的个数:互斥访问信号量为1,其余为资源数量

5.检查是否发生死锁:

①如果老和尚和小和尚都是先对tong进行P操作(先进行取水桶操作),则可能发生:三个老和尚同时取水,并取得水桶(此时完成了三个P(tong),则tong = 0),但是水缸中没有水(full = 0),即老和尚进程被阻塞在P(full);而若干个小和尚想去打水,水桶却被取光(tong = 0),即小和尚进城被阻塞在P(tong),这样就形成了死锁

②同理,也可能发生三个小和尚分别拿着桶,而水缸中水满(empty = 0),被阻塞在P(empty);而老和尚苦于没有水桶,被阻塞在P(tong)

解决方法:调整老和尚进程和小和尚进程的取桶顺序

老和尚先判断水缸中有没有水,水缸有水的情况下才去取桶喝水,即先P(full)再P(tong)

小和尚先判断水缸中有没有剩余容量,水缸中有剩余容量的情况下才去取桶打水,即先(empty)再P(tong)

1.确定函数的个数(2):所有生产者动作一致,故所有生产者视为一类进程;所有消费者动作一致,故所有消费者视为一类进程

2.确定函数的动作:

①动作是什么:

P生产产品,并将产品放入缓冲区

C从缓冲区取10个产品

②动作的次数:P和C都是不断重复 → while

3.确定函数是否在每个动作之前需要进行P操作:

①P生产产品前不需要消耗资源

P将产品放入缓冲区前需要消耗1个缓冲区剩余容量 → C从缓冲区取10个产品后增加10个缓冲区剩余容量(每取出1个产品,增加1个缓冲区容量,通过for循环实现)

②C从缓冲区取10个产品前需要消耗10个缓冲区产品数量(for循环实现) → P将产品放入缓冲区后增加1个缓冲区产品数量

③P和C对缓冲区的访问是互斥的(mutex)

④多个C之间P操作是互斥的:如果只是简单的使用for循环设置在取10个产品前,则可能发生多个C轮流的取产品

4.确定信号量的个数

5.检查是否发生死锁:否

.理发师问题 (进程是“服务与被服务”的关系)--2011

1.服务与被服务的关系

2.区别:需要额外设置变量记录当前等待的顾客有多少个,且该变量的访问是要互斥进行的,即需要夹在PV操作中

3.理发师问题实际上是生产者 - 消费者问题的变式:

①生产者 - 消费者问题:生产者生产资源,消费者消费资源;缓冲区限制资源上限

②理发师问题:将顾客和服务员分别视为一种资源

顾客:每个顾客到店时,生产一个顾客资源;在被服务前,消耗一个服务员资源

服务员:提供服务前,消耗一个顾客资源;确定有顾客时,生产一个服务员资源;再提供服务

特点:1.顾客无上限        2.服务员在没有顾客的时候可以休息,通过P(customer)实现

模板: 对num进行互斥加上下锁

int num; //有几个顾客等待被服务

Semaphore Lock=1; //互斥访问num

Semaphore rest=0; //同步信号量,用于实现“若没顾客,服务人员休息等待”  当前剩余资源的数量/让服务人员休息的队列

Semaphore wait=0; //同步信号量,用于实现“若服务员都很忙,顾客休息等待”(让顾客排队的队列,V(wait)让一个顾客不再等待)

Server(){                            Customer(){

  While(1){                              P(Lock);

      P(Lock);                           if(num>等位人数上限) {    //有些场景可能没有规定人数上限               

      if(num>0){    //有顾客                V(Lock);   

         num--;                            离开这家店;

         V(Lock);   //叫号                 }else{

         V(wait);   //唤醒一个顾客          num++;

         为顾客服务;                     V(Lock);

} else{           //没有顾客,解锁        V (rest); //唤醒一个正在休息的服务人员,但是不可能立即切换

V(Lock);                           P(wait); //等待被服务,先排队

P(rest);  //服务人员进入排队队列休息  被服务;

 }                                       }

}//while                              }//customer

}//Sever

注:先V的先V,再 P  

特点:顾客到店时,会检查waiting变量是否小于m,即等待数量有上限

.读者 - 写者问题 (特点:同类进程不互斥,异类进程互斥)

1.第一个进程上锁,最后一个进程解锁:通过count变量/多个count记录该进程正在使用资源数量

2.同类进程不互斥,不同类进程互斥(读者 - 写者问题的最主要特点)

3.写者进程不用判断是否自己是第一个/最后一个进程

4.所有的进程在访问int变量时,都要互斥访问,套PV

1.从南往北的车只要有一辆占据,其余从南到北的车就可以一直使用该路;同理从北往南的车(同类的进程可以共享资源,不同类的进程互斥资源)

2.申明count1变量和count2变量分别用于记录当前P1/P2有几个进程正在使用该临界资源,初始为0

3.不同的进程要互斥访问资源,同一个进程里的第一个人负责上锁,最后一个人负责解锁,在每个进程开始时,通过count是否为0判断自己是不是第一个进程,如果是,则对临界资源进行上锁

4.进行count++,表示自己正在使用临界资源,并在使用完临界资源后进行count--

5.在每个进程结束时,通过count是否为0判断自己是不是最后一个进程,如果是,则对临界资源进行解锁

模板:

int count=0; //同类进程的计数器

Semaphore Lock=1; //资源锁

Semaphore mutex=1; //对count互斥访问

A(){

P(mutex);

if(count==0);

P(Lock); //第一个负责上锁

count++;

V(mutex);

使用资源;

P(mutex);

If(count==1);

count--;

V(mutex);

}

类1:

从左往右的猴子是一类进程,共享绳索这个资源;从右往左的猴子是一类进程,共享绳索;而不同进程间,一个从右向左,一个从左向右,对绳索这一资源是互斥的

类2:

1、2、3种不同的录像片对应不同的进程,不同进程互斥访问录像厅(临界资源),统一进程共享录像厅

.哲学家进餐问题  --2019

特征:只有一类进程,且该类进程只有同时拥有多种资源才能进行  解决死锁

      A资源有n个,10个进程,每个都需要两个

第三个思路最通用:

①将每种资源通过int类型的变量定义(使用变量将资源数量具象化)---几类资源几个int变量

②在进程开始运行时,使用P(MUTEX)操作实现对各种资源进行互斥的访问,目的是逐一判断当前进程所需的各种资源是否满足运行的需要

③如果资源都满足,则拿走这些资源(一口气拿走),然后V(MUTEX),再执行动作

循环条件下:如果只要有一个资源不满足,则V(MUTEX),然后结束此次循环,进行下一次循环(continue);

只进行一次:如果只要有一个资源不满足,则使用goto语句返回函数的第一句重新进行判断(手动实现循环)

其中②实现同一时间只可能有一个进程在进行判断/拿走临界资源

最后完成动作归还资源时也要进行上锁,保证归还动作一气呵成的完成

模板:--这个方法不会让所有的进程都卡死--问题变态也就是多了一个int

int a = n;    //用int类型表示各种资源的剩余数量

int b = m;

semaphore mutex = 1;    //互斥信号量,同时仅允许一个进程判断并拿走临界资源

 //一口气拿走所有资源

Philosopher () {    //进行多次,while

    while (1) {

        P(mutex);  //上锁

        if (条件满足) {    //检查资源是否够用,一旦够用,将所需资源分配给该进程,并解锁

            a--; 或 a-3;  //所有的资源int值减少

            b--;

            将a和b分配给该进程; 或给进程分配3个资源

            V(mutex);

            break; //跳出while循环

        } else {    //资源不够,则解锁,并进行下一轮循环判断

            V(mutex);

            continue;

        }

        进行主体动作; //这人要干嘛了,说一下

        P(mutex);    //完成动作后,归还资源

        a++;

        b++;

        V(mutex);

}

Philosopher () {    //进行一次,使用goto

start:

    P(mutex);    //上锁

    if (条件满足) {

        a--;

        b--;

        将a和b分配给该进程;

        V(mutex);

    }

    else {

        V(mutex);

        goto start;

    }

    进行主体动作;

    P(mutex);    //上锁

    a++;    //归还a资源

    b++;    //归还b资源

    V(mutex);    //解锁

}

变量wan表示剩余碗的数量

数组a中a[i] = 1表示第i个哲学家的左手有筷子,a[(i + 1) % n] = 1表示第i个哲学家的右有筷子(需要对右手边的筷子进行取模操作,第n个哲学家的右手边筷子就是第1个哲学家左手的筷子)

②P(mutex)实现对临界资源的上锁

③判断wan变量和左右筷子是否都在,任意条件不满足则V(mutex)(解锁)并结束循环;条件都满足时,则对这两个变量进行 - 1操作,表示取出该临界资源

④V(mutex)实现对临界资源的解锁

⑥进餐(即自己的主体动作)

⑦归还拥有的临界资源 另一个哲学家进行上锁并判断

备注:PV操作只能对semaphore进行操作  

用第三种方法,筷子属于n类资源,因为两个哲学家之间的筷子只能分给左边或者右边

检查当前是否有4个盆和1个座位,再去完成打饭和坐落(主体动作)

①解法一:信号量

通用思路:

②解法二:int类型变量(此时每个干饭人只进行一次,不能使用continue)

int seat = m;    //剩余m个座位

int plate = n;    //剩余n个盘子

semaphore mutex = 1;    //互斥信号量

Eatman () {

start:

    进入餐厅;

    P(mutex);

    if (seat >= 4 && plate >= 1) {    //满足进餐条件,取走资源,并解锁

        seat -=4;

        plate--;

        V(mutex);

    }

    else {    //不满足进餐资源,解锁,并重新判断

        V(mutex);  //先把锁解了,再去等

        goto start;

    }

    干饭;

    P(mutex);

    plate += 4;    //干饭结束归还资源

    seat++;

    V(mutex);

}

6.读者 - 写者(写优先)

7.读者 - 写者(读写公平)

  1. 实现操作的先后顺序,没有互斥关系,设置同步信号量

Peterson算法:Peterson 算法用软件方法解决了进程互斥问题,遵循了空闲让进、忙 则等待、有限等待 三个原则,但是依然未遵循让权等待的原则。没有访问临界区的会卡在while

所有的解决方案都无法实现“让权等待”

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值