操作系统——P/V操作例题

1. (生产者—消费者问题)

        生产者、消费者共享有个初始为空、大小为n的缓冲区;

        只有缓冲区未满时,生产者才能把产品放入缓冲区;

        只有缓冲区非空时,消费者才能从中取出产品

semaphore mutex = 1;  // 互斥信号量
semaphore empty = n;  // 空闲缓冲区数量
semaphore full = 0;   // 产品(非空缓冲区)数量

void producer(){
    while(true){
        生产产品;
        P(empty);
        P(mutex);
        产品放入缓冲区;
        V(mutex);
        V(full);  // 唤醒消费者进程
    }
}

void consumer(){
    while(true){
        P(full);
        P(mutex);
        从缓冲区取出一个产品;
        V(mutex);
        V(empty);  // 唤醒生产者进程
        使用产品;
    }
}

2.(吸烟者问题)

        假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供
应者就会放另外两种材料再桌上,这个过程一直重复 (让三个抽烟者轮流地抽烟)

semaphore offer1 = 0;  // 组合1(纸+胶水)的数量
semaphore offer2 = 0;  // 组合2(烟草+胶水)的数量
semaphore offer3 = 0;  // 组合3(烟草+纸)的数量
semaphore finish = 0;  // 抽烟是否完成
int i = 0;             // 用于轮流提供

void provider(){
    while(true){
        if(i == 0){
            将组合1放桌上;
            V(offer1);
        }
        else if(i == 1){
            将组合2放桌上;
            V(offer2);
        }
        else if(i == 2){
            将组合3放桌上;
            V(offer3);
        }
        i = (i+1) % 3;
        P(finish);
    }
}

void smoker1(){
    while(true){
        P(offer1);
        拿走组合1,抽掉;
        V(finish);
    }
}

void smoker2(){
    while(true){
        P(offer2);
        拿走组合2,抽掉;
        V(finish);
    }
}

void smoker3(){
    while(true){
        P(offer3);
        拿走组合3,抽掉;
        V(finish);
    }
}

3.(读者—写者问题)

        有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:

        ①充许多个读者可以同时对文件执行读操作:

        ②只充许一个写者往文件中写信息:

        ③任一写者在完成写操作之前不允许其他读者或写者工作:

        ④写者执行写操作前,应让已有的读者和写者全部退出。

semaphore rw = 1;     // 写文件的互斥访问
int count = 0;        // 记录当前有几个读进程在访问
semaphore mutex = 1;  // count的互斥访问

void writer(){
    while(true){
        P(rw);
        写文件;
        V(rw);
    }
}

void reader(){
    while(true){
        P(mutex);
        if(count == 0){
            P(rw);
        }
        count++;
        V(mutex);

        读文件;

        P(mutex);
        count--;
        if(count == 0){
            V(rw);
        }
        V(mutex);
    }
}

4.(哲学家就餐问题)

        一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上有一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。

        要求使用以下策略解决死锁:仅当哲学家左右两支筷子都可用时才允许他抓起筷子。

semaphore chopstick[5] = {1,1,1,1,1};
semaphore mutex = 1;    // 互斥取筷子

void Pi(){
    while(true){
        P(mutex);
        P(chopstick[i]);       // 拿左筷子
        P(chopstick[(i+1)%5]); // 拿右筷子
        V(mutex);
        吃饭;
        V(chopstick[i]);       // 放左筷子
        V(chopstick[(i+1)%5]); // 放右筷子
        思考;
    }
}

5.(简单奇偶数统计) 

        缓冲区的容量为N。

        P1每次用produce()生成一个正整数并用put()将其放入缓冲区;

        P2每次用getOdd()从缓冲区中取出一个奇数并用countOdd()统计奇数的个数;

        P3每次用getEven()从缓冲区中取出一个偶数并用countEven()统计偶数的个数。

semaphore empty = N;  // 缓冲区空闲量
semaphore mutex = 1;  // 互斥访问缓冲区
semaphore odd = 0;    // 奇数统计
semaphore even = 0;   // 偶数统计

void P1(){
    while(true){
        int i = produce();
        if(i%2 == 0){
            P(mutex);
            put();
            V(mutex);
            V(even);
        }
        else{
            P(mutex);
            put();
            V(mutex);
            V(odd);
        }
    }
}

void P2(){
    while(true){
        P(odd);
        P(mutex);
        getOdd();
        countOdd();
        V(mutex);
        V(empty);
    }
}

void P3(){
    while(true){
        P(even);
        P(mutex);
        getEven();
        countEven();
        V(mutex);
        V(empty);
    }
}

6.(桥梁通行)

        桥上不允许有两车相向而行,但允许同方向最多五辆车通行。使用信号量操作实现交通管理。(提示:进程可分为两类:自东向西的车辆和自西向东的车辆)

semaphore bridge = 1;  // 行车方向的互斥访问
semaphore empty = 5;   // 单向剩余容量
semaphore mutex_west = 1;
semaphore mutex_east = 1;
int west_count = 0;  // 自西向东的第几辆车
int east_count = 0;  // 自东向西的第几辆车

void WestToEast(){
    while(true){
        P(mutex_west);
        if(west_count == 0){  // 第一个上桥
            P(bridge);
        }
        west_count++;
        V(mutex-west);

        P(empty);
        过桥;
        V(empty);
    
        P(mutex_west);
        west_count--;
        if(west_count == 0){  // 最后一个上桥
            V(bridge);
        }
        V(mutex-west);
    }    
}

void EastToWest(){
    while(true){
        P(mutex_east);
        if(east_count == 0){  // 第一个上桥
            P(bridge);
        }
        east_count++;
        V(mutex-east);

        P(empty);
        过桥;
        V(empty);
    
        P(mutex_east);
        east_count--;
        if(east_count == 0){  // 最后一个上桥
            V(bridge);
        }
        V(mutex-east);
    }
}

7.(图书馆登记)

        有一阅览室,共有100个座位。读者进入时必须现在登记表上进行登记。该表表目设有座位号和读者名;离开时需要将其登记项擦除。

semaphore seats = 100;
semaphore mutex = 1;

void lib(){
    while(true){
        P(seats);  // 占有座位
        P(mutex);
        登记信息;
        V(mutex);

        阅读;

        P(mutex);
        注销信息;
        V(mutex);
        V(seats);  // 释放座位
    }
}

8.(考场)

        假设把学生和监考老师都看做进程,学生有N人,教师有1人。考场门口每次只能进出一个人,进考场的原则是先来先进。当N个学生都进入了考场后,教师才能发卷子。学生交卷后即可离开考场,教师要等收上全部卷子后封装才能离开考场。

semaphore door = 1;         // 是否能进出门
semaphore stduentReady = 0; // 学生是否到齐
semaphore examBegin = 0;    // 考试开始
semaphore examEnd = 0;      // 考试结束

int sudentNum = 0;    // 学生数量
semaphore mutex1 = 1; // 学生人数统计互斥
int paper = 0;        // 已交试卷数
semaphore mutex2 = 1; // 试卷数统计互斥

void student(){
    while(true){
        P(door);
        进门;
        V(door);
        
        P(mutex1);
        studentNum++;
        if(studentNum == N){
            V(studentReady);  // 触发开始考试
        }
        V(mutex1);
        
        P(examBegin);    // 等待考试开始
        考试;
        交卷;
        P(mutex2);
        paper++;
        if(paper == N){
            V(examEnd);
        }
        V(mutex2);

        P(door);
        出门;
        V(door);
    }
}

void teacher(){
    while(true){
        P(door);
        进门;
        V(door);

        P(studentReady);
        发试卷;
        V(examBegin);
        P(examEnd);  // 等待考试结束
        封装试卷;
        
        P(door);
        出门;
        V(door);
    }
}

posted @ 2024-07-01 00:44  Unalome  阅读(37)  评论(0编辑  收藏  举报  来源