zoukankan      html  css  js  c++  java
  • 操作系统-PV习题

    (1)阅览室问题:加入阅览室入口有一本登记册,每个人都必须按顺序签名进去。

    想法:登记册可以用结构数组A[]表示,包含name和number。此外,还需要信号量seatcount表示剩余座位数。
    使用信号量mutex约束每次只有一个人能修改登记册
    struct { 
        char name[10]; 
        int number;
    }A[100];
    semaphore mutex = 1; //控制A[]被修改的信号量
    semaphore seatcount = 100; //剩余的座位数
    int i;
    for(i=0; i<100; i++) {
        A[i].number=i;
        A[i].nume=null;
    }
    cobegin
    process readeri(char readername[]) {
        P(seatcount);
        P(mutex);
        for(int i=0; i<100; i++) {
            if(A[i].name==null) A[i].name=readername;
            reader get the seat number i;
        }
        V(mutex);
        {进入阅览室座位号i,坐下读书};
        P(mutex);
        A[i].name = null;
        V(mutex);
        V(seatcount);
    }
    coend
    (2)四个进程Pi(i=0…3)和四个信箱Mj(j=0…3),进程间借助相邻信箱传递消息,即Pi每次从Mi中取一条消息,经加工后送入M(i+1)mod4,其中M0、M1、M2、M3分别可存放3、3、2、2个消息。初始状态下,M0装了三条消息,其余为空。试以P、V操作为工具,写出Pi(i=0…3)的同步工作算法。
    想法:说穿了还是有缓冲区的生产者消费者问题,每个信箱需要用信号量empty表示剩余空间、full表示剩余信件。此外还需要int数in、out指明信箱中存取信的位置,以及对应信号量mutex。
    semaphore mutex1 = mutex2 = mutex3 = mutex0 = 1; //约束每个信箱同一时间只能有一个进程操作
    semaphore empty0 = 0 , empty1 = 3 , empty2 = empty3 =2; //信箱剩余空间
    semaphore full0 = 3 , full1 = full2 = full3 =0; //信箱剩余信件数
    int in0 = in1 = in2 = in3 = out0 = out1 = out2 = out3 =0; //信箱中存、取信的位置,初始均为0
    cobegin
    process P0( ) {
        while(true) {
            P(full0);
            P(mutex0);
            {从M0[out0]取一条消息};
            out0 = ( out0 + 1 ) % 3;
            V(mutex0);
            V(empty0);
            {加工消息};
            P(empty1);
            P(mutex1);
            {消息存M1[in1]};
            in1 = ( in1 + 1 ) % 3;
            V(mutex1);
            V(full1);
        }
    }
    /*P1-P3略*/
    coend    
    (3)今有k个进程,它们的标号依次为1~k,如果允许它们同时读文件file,但必须满足条件:参加同时读文件的进程的标号之和需小于M(k<M)
    想法:用一个数numbersum记录当前读文件的进程标号之和,通过信号量mutex实现对其的互斥操作
    如果进程发现自己不能运行,就要P(waits)把自己阻塞,阻塞后因为其还在numbersum的临界区内,因此其它进程也进不来了;每当读文件完成,释放一个等待的进程;被释放的进程再次检测自己能否运行,不能的话继续P(waits)把自己阻塞
    semaphore waits = 0;
    Semaphore mutex = 1;
    int numbersum = 0;
    cobegin
    process readeri(int number) {    
        P(mutex);
        while(numbersum+number>=M) {
            V(mutex);
            P(waits);
        }
        numbersum = numbersum + number;
        V(mutex);
        Read file;
        P(mutex);
        numbersum = numbersum - number;
        V(waits); 
        V(mutex);
    }
    coend
    (5)轮流捡黑、白棋子:其实就是最简单的生产者消费者问题
    semaphore s1 = 1; //可捡白子
    semaphore s2 = 0; //可捡黑子
    process p1() {
        while(true) {
            P(s1);
            捡白子;
            V(s2);
        }
    }
    process p2() {
        while(true) {
            P(s2);
            捡白子;
            V(s1);
        }
    }
    南大13年真题:A捡黑子并计数,B捡白子并计数。不要求轮流捡,但要求互斥捡。C等待AB完成后,合计计数。
    想法:通过互斥信号量mutex实现A和B互斥捡棋子。计数器则不需要互斥,因为黑子、白子是分两个计数器;A和B计数完成后各自V(allow),从而允许C工作
    Semaphore allow = -1;
    Semaphore mutex = 1;
    int count = count_black = count_black = 0;
    process A(){
        while(true){
            P(mutex);
            get(black);
            V(mutex);
            if(取到了){count_black++;}
            else break;
        }
        V(allow);
    } 
    process B(){
        while(true){
            P(mutex);
            get(write);
            V(mutex);
            if(取到了){count_write++;}
            else break;
        }
        V(allow);
    }
    process C(){
        P(allow);
        count = count_black + count_write;
        printf();
    }
    (6)n1个进程通过m个缓冲区向n2个缓冲区发消息,每条消息n2个接收进程都要各自接收一次。
    思路:课本答案的做法是把这一组缓冲区看成n2组缓冲区(每组m个),每个发送进程需要同时写n2个缓冲区。但是我觉得答案做法很迷啊,m个缓冲区直接被它强行变成了n2*m个缓冲区,每次写一个、接收n2次,变成了每次写n2个、接收n2次。而且答案明明把缓冲区分为n2组,但是只有一个信号量mutex实现对缓冲区操作的互斥。
    semaphore mutex , empty[n2] , full[n2];
    int i;
    mutex = 1;
    for(i=1; i<n2; i++) {
        empty[i]=m;
        full[i]=0;
    }
    cobegin
    send() {           
        for(int i=0;i<n2;i++) {
            P(empty[i]);
            P(mutex);
            {将消息放入缓冲区;}
            V(mutex);
        }
        for(int i=0;i<n2;i++){
            V(full[i]);
        }
    }
    receive() {       
        for(int i=0;i<n2;i++) {
            P(full[i]);
            P(mutex);
            {从缓冲区中取出信息;}
            V(mutex);
        }
        for(int i=0;i<n2;i++) {
            V(empty[i]);
        }
    }
    coend
    (7)生产者进程每次写3个缓冲区,消费者进程每次读一个缓冲区
    思路:答案的思路是通过信号量s1控制每次只允许一个生产者写,通过信号量s2控制每次只允许一个消费者读。因此本题生产者和消费者可以同时工作。
    定义了一个初始为0的int数count,每次消费都将其加1,每三次消费之后count达到3,才V(sput)一次,允许一次生产;每次生产之后进行三次V(sget)允许三次消费。
    int buf[9];
    int count = getptr = putptr = 0;
    semaphore s1 = s2 = 1;
    Semaphore sput = 1;
    Semaphore sget = 0;
    cobegin
    process producer_i() {
        while(true) {
            P(sput);
            P(s1);
            buf[putptr] = 1;
            putptr = ( putptr + 1 ) % 9;
            buf[putptr] = 2;
            putptr = ( putptr + 1 ) % 9;
            buf[putptr] = 3;
            putptr = ( putptr + 1 ) % 9;
           V(sget);
            V(sget);
            V(sget);
            V(s1);        
        }
    }
    process consumer_j() {
        int y;
        while(true) {
           P(sget);
            P(s2);
            y = buf[getptr];
            getptr = ( getptr + 1 ) % 9;
            count++;
            if(count==3){
                count = 0;
               V(sput);
            }
            V(s2);
            消费整数y;
        }
    }
    coend
    (8)有三组工人和N个槽,第一组工人生产车架,第二组工人生产车轮,第三组工人用车架和四个车轮生产一辆车
    思路:其实就是上一题的生产者消费者问题的加强版,可以把N个槽分为N/5、4N/5两部分,分别装车架和车轮,否则可能会出现装满车架或车轮的情况。
    通过信号量mutex1控制每次只有一个进程操作第一个槽(即只有1个生产者放车架或1个消费者拿车架);通过mutex2控制每次只有一个进程操作第二个槽(即只有一个生产者放车轮或1个消费者拿车轮)。
    每生产一个车架就可以直接拿(不需要像车轮那样通过计数器count控制),因此每次生产一个车架都V(s3)一次。
    每生产四个车轮才能拿一次,因此定义了一个初始为0的int数count,每次生产车轮都将其加1,count达到4时才V(s4)一次。因为有mutex2的存在,因此每次只有一个进程能修改count。
    semaphore mutex1 = mutex2 = 1;
    semaphore s1 = N/5 , s2 = 4N/5 , s3 = s4 = 0;
    int count = 0;
    int in1 = in2 = out1 = out2 = 0;
    cobegin
    process worker1() {
        while(true) {
            加工一个车架;
            P(s1);
            P(mutex1);
            车架放入box[in1];
            in1 = (in1 +1) % (N/5);
            V(mutex1);
            V(s3);
    }
    process worker2() {
        while(true) {
            加工一个车轮;
            P(s2);
            P(mutex2);
            车架放入box[in2];
            in2 = (in2 +1) % (4N/5);
            count = count + 1;
            if(count==4) {
                count = 0;
                V(s4);
            }
            V(mutex2);
    }
    process worker3() {
        while(true) {
            P(s3);
            P(mutex1);
            从box[out1]拿车架;
            out1 = (out1 + 1) % (N/5);
            V(mutex1);
            V(s1);
            P(s4);
            P(mutex2);
            从box[out2]开始取四个车轮;
            out2 = (out2 + 4) % (4N/5);
            V(s2);
            V(mutex2);
            装配车子;
        }
    }
    ceend
    (9)有一个仓库,可存放X、Y两种产品,仓库的存储空间足够大,但要求:(1) 每次只能存入一种产品X或Y, (2) 满足-N<X-Y<M
    想法:可以设置两个信号量来控制X、Y产品的存放数量关系:
    sx表示当前允许X产品比Y产品多入库的数量,即在当前库存量和Y产品不入库的情况下,还可以允许sx个X产品入库,初始时,若不放Y而仅放X产品,则sx最多为M-1个;
    sy表示当前允许Y产品比X产品多入库的数量,即在当前库存量和X产品不入库的情况下,还可以允许sy个Y产品入库,初始时,若不放X而仅放Y产品,则sy最多为N-1个。
    当往库中存放入一个X产品时,则允许存入Y产品的数量也增加1,故信号量sy应加1;当往库中存放入一个Y产品时,则允许存入X产品的数量也增加1,故信号量sx应加1。
    semaphore mutex=1;         
    semaphore sx = M-1;
    semaphore sy = N-1;
    cobegin
    process storeX( ) {
        while(true) {
            P(sx);
            P(mutex);
           {将X产品入库};
           V(mutex);
            V(sy);
        }
    }
    process storeY( ) { 
        while(true) {
           P(sy);
           P(mutex);
           {将Y产品入库};
           V(mutex);
           V(sx);
        }
    }
    coend
    (10)有一个仓库,可放入A、B两种产品,最大库容量各为m个,生产车间不断地取A、B进行装配,每次各取一个。为了零件腐蚀,必须按照先入库者先出库的顺序。有两组供应商分别不断地供应A和B,每次一个。为了保证配套和库存合理,当某种零件比另一种超过n个时,暂停对数量大的零件的进货。
    想法:这题实际是上一题的强化版,按照题意一共四种约束关系:0≤A≤m、0≤B≤m、B-A≤n、A-B≤n,分别通过信号量empty1、full1、empty2、full2、sa、sb进行控制。
    答案是通过mutex约束每次只有一个进程操作仓库。其实也可以把约束条件放得更宽泛些。
    semaphore empty1 , empty2 , full1 , full2 , mutex , sa , sb;
    int in1 , in2 , out1 , out2;
    empty1 = empty2 = m; //剩余可放空间
    full1 = full2 = 0; //剩余产品数
    sa = sb = n;
    mutex = 1;
    in1 = in2 = out1 = out2 = 0;
    cobegin
    process put_A() {
        while(true) {
            P(empty1);
            P(sa);
            P(mutex);
            把A零件放入buffA[in1];
            in1 = (in1 + 1) % m;
            V(mutex);
            V(sb);
            V(full1);
        }
    } 
    process put_B() {
        while(true) {
            P(empty2);
            P(sb);
            P(mutex);
            把B零件放入buffB[in2];
            in2 = (in2 + 1) % m;
            V(mutex);
            V(sa);
            V(full2);
        }
    } 
    process get() {
        while(true) {
            P(full1);
            P(full2);
            P(mutex);
            从buffA[out1]取A零件;
            从buffB[out2]取B零件;
            out1 = (out1 + 1) % m;
            out2 = (out2 + 1) % m;
            V(mutex);
            V(empty1);
            V(empty2);
            把A和B装配成产品;       
        }
    }
    coend
    因为装配时A和B各取一件,所以对它们的相对关系并无影响,因为无需对信号量sa和sb进行修改。
    答案用了信号量mutex约束三个进程不能同时工作,其实我觉得应该改用三个信号量。
    (11)能容纳500人的博物馆,每次只能一个人进出
    思路:使用mutex约束每次只有一个人使用门。本题必须注意,进门与出门操作必须在P(empty)和V(empty)之间的临界区内,即有空位才能进门,出门后才释放空位
    Semaphore empty = 500;
    Semaphore mutex = 1;
    cobegin
    process_i(){
        P(empty);
        P(mutex);
        进门;
        V(mutex);
        参观;
        P(mutex);
        出门;
        V(mutex);
       V(empty);
    }
    (12)三个线程增加互斥条件
    typedef struct{
        float a;
        float b;
    }cnum;
    cnum x , y ,z;
    cnum add(cnum p ,cnum q){
        cnum s;
        s.a = p.a + q.a;
        s.b = s.b + q.b;
        return s;
    }
    想法:本题先看代码,thread1和thread2会修改w,但是w是它们自身创建的,其它线程也没有使用到;而thread3则修改了z、y;
    thread3会修改z,而thread2会访问z,必须定义信号量使它们互斥访问z;
    thread3会修改y,而thread1和thread2都会访问y,因此需要定义互斥信号量mutex_y1使thread1和thread3对y互斥访问、定义互斥信号量mutex_y2使thread2和thread3对y互斥访问(thread2和thread3不需要互斥y)
    Semaphore mutex_y1 = 1;  //线程1、3对y的互斥访问
    Semaphore mutex_y2 = 1;  //线程2、3对y的互斥访问
    Semaphore mutex_z = 1;   //线程2、3对z的互斥访问
     
    thread1{
        cnum w;
        P(mutex_y1);
        w = add(x , y);
        V(mutex_y1);
    }    
    thread2{
        cnum w;
        P(mutex_y2);
        P(mutex_z);
        w = add(y , z);
        V(mutex_z);
        V(mutex_y2);
    }    
    thread3{
        cnum w;
        w.a = 1;
        w.b = 1;
        P(mutex_z);
        z = add(z , w);
        V(mutex_z);
        P(mutex_y1);
        P(mutex_y2)
        y = add(y , z);
        V(mutex_y1);
        V(mutex_y2);
    }    
    (13)14年南大真题:缓冲区可放2000字节,P进程读入数据到缓冲区,Q1、Q2从缓冲区取数据并计算加工,并把结果打印出来。
    题目给的子程序:read20()从输入设备读20个字数据到缓冲区;
                                 get20()从缓冲区取20字节;
                                 comp40t30()计算加工40个字得到结果30字节;
                                 print15()打印15字节
    Semaphore mutex = 1;
    Sempahore full = 1;
    Semaphore empty = 100;
    process P(){
        P(empty);
        P(mutex);
        read20();
        V(mutex);
        V(full);
    }
    Process Q1(){
        P(full); get20();
        P(full); get20();
        comp40t30();
        V(empty); print15;
        V(empty); print15;
    }
     
  • 相关阅读:
    UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design
    UVa 1658 (拆点法 最小费用流) Admiral
    UVa 11082 (网络流建模) Matrix Decompressing
    UVa 753 (二分图最大匹配) A Plug for UNIX
    UVa 1451 (数形结合 单调栈) Average
    UVa 1471 (LIS变形) Defense Lines
    UVa 11572 (滑动窗口) Unique Snowflakes
    UVa 1606 (极角排序) Amphiphilic Carbon Molecules
    UVa 11054 Wine trading in Gergovia
    UVa 140 (枚举排列) Bandwidth
  • 原文地址:https://www.cnblogs.com/yangyuliufeng/p/10713095.html
Copyright © 2011-2022 走看看