文章目录

  • 生产者、消费者问题描述
  • PV操作题目分析步骤
  • 多生产者、多消费者问题描述
  • 问题分析
  • 吸烟者问题描述
  • 问题分析


生产者、消费者问题描述

系统中有一组生产者进程和一组消费者进程,生产者进程每次生成一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。(注:这里的“产品”理解为某种数据)
生产者、消费者共享一个初始为空、大小为n的缓冲区。
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。
缓冲区是临界资源,各进程必须互斥地访问。

PV操作题目分析步骤

  1. 关系分析,找出题目中描述的各个进程,分析它们之间的同步互斥关系。
  2. 整理思路。根据各进程的操作流程确定P、V操作的大致顺序。
  • 生产者每次要消耗(P)一个空闲缓冲区,并生产(V)一个产品。
  • 消费者每次消耗(P)一个产品,并释放一个空闲缓冲区(V)
  • 往缓冲区放入/取走产品需要互斥。
  1. 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值(互斥信号量初值一般为1,同步信号量的初值要看对应资源的初始值是多少)
semaphore mutex = 1;    //互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;    //同步信号量,表示空闲缓冲区的数量
semaphore full = 0;     //同步信号量,表示产品的数量,也即非空缓冲区的数量

producer (){
    while(1){
        生产一个产品;
        P(empty);
        P(mutex);
        把产品放入缓冲区;
        V(mutex);
        V(full);
    }
}

consumer (){
    while(1){
        P(full);
        P(mutex);
        从缓冲区取出一个产品;
        V(mutex);
        V(empty);
        使用产品
    }
}
  • 实现互斥的P操作一定要在实现同步的P操作之后,否则会导致“死锁”
  • V操作不会导致进程阻塞,因此两个V操作顺序可以交换。

多生产者、多消费者问题描述

桌子上有一个盘子,每次只能向其中放入一个水果,爸爸专向盘子中放苹果,妈妈放橘子,儿子吃盘子中的橘子,女儿吃苹果。只有盘子空时,爸爸妈妈才能放一个水果,仅当盘子中有需要的水果时,儿子女儿才可以从盘子中取出水果。
用PV操作实现上述过程

问题分析

  1. 关系分析:
  • 互斥关系:对缓冲区(盘子)的访问要互斥地进行
  • 同步关系
  • 父亲将苹果放入盘子后,女儿才能取苹果
  • 母亲将橘子放入盘子后,儿子才能取橘子
  • 只有盘子为空时,父亲或母亲才能放水果
  1. 整理思路,根据进程地操作流程确定P、V操作的大致顺序(互斥:在临界区前后分别PV。同步:前V后P)
  2. 设置信号量
semaphore mutex = 1;    //实现互斥访问盘子(缓冲区)
semaphore apple = 0;    //盘子中有几个苹果
semaphore orange = 0;   //盘子中有几个橘子
semaphore plate = 1;    //盘子中还可以放多少个水果

dad (){
    while(1){
        准备一个苹果;
        P(plate);
        P(mutex);
        把苹果放入盘子;
        V(mutex);
        V(apple);
    }
}

mom (){
    while(1){
        准备一个橘子;
        P(plate);
        P(mutex);
        把橘子放入盘子;
        V(mutex);
        V(orange);
    }
}

daughter (){
    while(1){
        P(apple);
        P(mutex);
        从盘中取出苹果;
        吃掉苹果;
        V(mutex);
        V(plate);
    }
}

son (){
    while(1){
        P(orange);
        P(mutex);
        从盘中取出橘子;
        吃掉橘子;
        V(mutex);
        V(plate);
    }
}

吸烟者问题描述

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

问题分析

  1. 关系分析
  • 桌子可以抽象为容量为一地缓冲区,要互斥访问
  • 同步关系(组合一:纸、胶水;组合二:烟草、胶水;组合三:烟草、纸)
  • 桌子上有组合一:第一个抽烟者取走
  • 桌子上有组合二:第二个抽烟者取走
  • 桌子上有组合三:第三个抽烟者取走
  • 发出完成信号:供应者将下一个组合放到桌上
  1. 整理思路
  2. 设置信号量
semaphore offer1 = 0;   //桌子上组合一地数量
semaphore offer2 = 0;   //桌子上组合二地数量
semaphore offer3 = 0;   //桌子上组合三地数量
semaphore finish = 0;   //抽烟是否完成
int i = 0;  //用于实现“三个抽烟者轮流抽烟”

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

smoker1 (){
    while(1){
        P(offer1);
        从桌上拿走组合一;卷烟;抽掉;
        V(finish);
    }
}

smoker2 (){
    while(1){
        P(offer2);
        从桌上拿走组合一;卷烟;抽掉;
        V(finish);
    }
}

smoker3 (){
    while(1){
        P(offer3);
        从桌上拿走组合一;卷烟;抽掉;
        V(finish);
    }
}