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;
    }
     
  • 相关阅读:
    VS2012 打包部署程序
    请求筛选模块被配置为拒绝包含 hiddenSegment 节的 URL 中的路径
    “远程服务器返回错误: (404) 未找到”的正确解决方法
    23.IDEA 运行junit单元测试方法
    Java单元测试之JUnit篇
    22.IntelliJ IDEA 切换 project
    21. 【intellij idea】Project Structure 讲解
    一个多maven项目聚合的实例
    解决Maven项目相互依赖/循环依赖/双向依赖的问题
    20. idea刷新项目、清除项目缓存
  • 原文地址:https://www.cnblogs.com/yangyuliufeng/p/10713095.html
Copyright © 2011-2022 走看看