目录:

一、生产者、消费者问题

(1)单生产者、消费者

(2)多生产者、消费者

(3)真题练习


       生产者、消费者问题经常是考试重点,因此对此问题的掌握是关键的。本文将会针对典型的生产者、消费者问题由简入难,由浅入深。最后提供几个考研真题练习一下,为求完全掌握该类问题。

(1)单生产者、消费者

问题描述:

有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区;消费者进程每次从有界缓冲区中取出一个产品并使用。生产者和消费者共享一个初始为空、大小为n的缓冲区。

问题分析:

      此问题需要两个进程,分别是生产者和消费者进程,还需要一个互斥信号量mutex(缓冲区),其mute=1表示只允许一个进程进入缓冲区;两个资源信号量:未开始生产之前empty=n,full=0即产品一共可以存放n个,目前只有0个。

伪代码:

    
semaphore mutex=1,empty=n,ful1=0; //初始化信号量 
//生产者进程
        void producer(){
              do {
                 生产者生产产品;
                 P(empty)       //判断缓冲区是否为空 
                 P(mutex);      //判断是否可以进入缓冲区,空则进入
                  将产品放入指定区域;
                 V(mutex);      //退出临界区,允许别的进程进入 
                 V(full);        //缓冲池中非空的缓冲区数量加1,同时唤醒等待的消费者进程
                  }while(true);
                        }
//消费者进程
           void consumer(){
              do{
                P(full);       //判断缓冲区是否非空(是否有产品)
                P(mutex);       //判断是否可以进入缓冲区(非空则进入)
                 取走产品;
                V(mutex);        //退出临界区,允许别的进程进入
                V(empty);        //缓冲池中空缓冲区数量加1,可以唤醒等待的生产者进程
                         }
                  使用产品;
                           }

       通过上面的伪代码,可以发现,在每个进程中用于实现互斥的P(mutex)和V(mutex)操作必须成对的出现,并且要出现在同一个进程中;注意:每个程序中的多个P、V操作顺序不能颠倒,比如在生产者进程,应先执行对资源信号量是否为空的检查,执行P操作–P(empty);再执行进入缓冲区的P操作–P(mutex),否则可能会因为发生互斥而产生死锁现象,即进入缓冲池但是没有空闲的缓冲区(empty\neq0),生产者进程会发生阻塞,而别的进程又无法进入临界区,从而导致进程发生死锁。 

(2)多生产者--消费者问题
问题描述
     桌子上有一个盘子,每次只能向其中放入一个水果。爸爸只向盘子中放苹果,妈妈只向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子为空时,爸爸妈妈才能往盘子里放一个水果,仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。
问题分析

       盘子就是一个缓冲区,且只允许一个进程进入,因此需要一个互斥信号量mutex。当盘子为空时,父亲可以进入缓冲区往盘子里放苹果,或者妈妈进入缓冲区往里面放橘子;此时盘子里面有东西,儿子发现不为空且盘子里放的是橘子,则进入缓冲区拿橘子并吃掉,如果为苹果则女儿拿起吃掉。一共四个进程,此时还需要三个资源信号量apple orange以及plate来表示盘子是否有东西,有东西该东西是什么,进而确定是否可以访问缓冲区。

伪代码:

//定义信号量
semaphore mutex = 1;  //实现互斥访问盘子(缓冲区)
semaphore apple = 0;  //盘子中有几个苹果
semaphore orange = 0;  //盘子中有几个橘子
semaphore plate = 1;   //盘子中还可以放多少个水果
  //进程一:父亲
           dad(){
                while(1){
                     准备一个苹果;
                    P(plate);    //看盘子里是否可以放水果
                    P(mutex);    //进入临界区
                       把苹果放入盘子;
                    V(mutex);    //退出临界区同时唤醒女儿进行拿苹果
                    V(apple);    //苹果数量+1
                        }
                  }
  //进程二:母亲
            mom(){
                while(1){
                     准备一个橘子;
                  P(plate);      //看盘子里是否可以放水果
                  P(mutex);      //进入临界区
                     把橘子放入盘子;
                  V(mutex);      //退出临界区同时唤醒儿子进行拿橘子
                  V(orange);     //橘子数量+1
                          }
                 }
 //进程三:女儿
           daughter(){
               while(1){
  
                  P(apple);         //判断是否有苹果可以取
                  P(mutex);         //进入临界区,互斥访问
                   从盘子中取出苹果;
                   V(mutex);         //退出临界区
                   V(plate);         //盘子里水果数量-1
                     吃苹果;
                         }
                       }
  //进程四:儿子

              son(){
                  while(1){
  
                    P(orange);         //判断是否有橘子可以取
                    P(mutex);          //进入临界区,互斥访问
                       从盘子中取出橘子;
                    V(mutex);         //退出临界区
                    V(plate);          //盘子里水果数量-1
                       吃掉橘子;
                           }
                       }

(3)真题练习

问题描述

在一个仓库中可以存放A和B两种产品,要求:
①每次只能存入一种产品。
②A产品数量-B产品数量<M。③B产品数量-A产品数量<N.
其中,M,N是正整数,试用P操作、V操作描述产品A与产品B的入库过程。

问题分析

     使用信号量mutex控制两个进程互斥访问临界资源(仓库),使用同步信号量Sa和Sb(分别代表产品A与B的还可容纳的数量差,以及产品B与A的还可容纳的数量差)满足条件2和条件3。

       对于②,B产品数量=0,且产品数量为正整数,那么A产品数量=M-1;同理,令A产品数量=0,那么B产品数量=N-1.

      一共两个进程,分别Sa存放进程(process_A)和Sb存放进程(process_B);三个信号量SaSbmutex

代码如下:

//定义信号量
Semaphore Sa=M-1,Sb=N-1;
Semaphore mutex=l;            //访问仓库的互斥信号量 
//进程一
     process_A(){ 
            while(l){
                  P(Sa);     //看Sa是否还可以存入
                  P(mutex);  //Sa数量小于M-1,则进入互斥缓冲区
                    A产品入库;
                  V(mutex);  //退出缓冲区
                 V(Sb);      //唤醒进程b
                    }
                }
    
//进程二
      process_B(){ 
            while(1){ 
                 P(Sb);      //看Sb是否还可以存入
                 P(mutex);   //Sb数量小于N-1,则进入互斥缓冲区
                   B产品入库; 
                 V(mutex);   //退出缓冲区
                 V(Sa);      //唤醒进程a
                      }
                 }

(4)真题练习

问题描述

      面包师有很多面包,由n名销售人员推销。每名顾客进店后取一个号,并且等待叫号,
当一名销售人员空闲时,就叫下一个号。试设计一个使销售人员和顾客同步的算法。

问题分析

    一共两个进程,顾客取号进程(Consumer)和销售人员叫号进程(Seller)。四个信号量 i,j,mutex_i,mutex_j;为啥互斥信号量不是一个而选择两个呢,是因为顾客取号和销售人员叫号需要两个值i和j,两个值的增加不能在一个缓冲区中,是相互独立互不影响的,否则无法正确进行对应值的增加。鄙人这样理解:取号和叫号是两个不同的程序,比如取号是用一台机器取号,而叫号则是服务员通过另一台机器或者人工叫号,使用不同的机器或者过程,因此需要区分不同的互斥信号量。

代码如下:

//定义信号量
int i=0,j=0;                 //i表示顾客取号值,j表示销售者叫号值,都初始化为0
semaphore mutex_i=1,mutex_j=1;
//顾客进程
      Consumer(){
             首先顾客进入面包店;
             P(mutex_i);      //进入取号临界资源区,互斥访问i
             进行取号i;
             i++;            //号加1
            V(mutex_i);      //取完号离开取号资源区
           等待叫号i并购买面包;
                }
//销售人员进程
      Seller(){
           (while(1){
           P(mutex_j);       //销售者进去交好资源区,互斥访问
            if(j<i)
               {
                叫号j;
               j++;         //叫完号后j数量加1
           V(mutex_j);      //离开叫号资源区
           销售面包;
                }
           else{
               V(mutex_j);   //暂时没有顾客,离开叫号区
              休息片刻;
                        }
               }
               

(5)真题练习

问题描述

系统中有多个生产者进程和多个消费者进程,共享一个能存放 100件产品的环形缓冲区(初始为空)。缓冲区未满时,生产者进程可以放入其生产的一产品,否则等待;缓冲区未空时,消费者进程可从缓冲区取走一件产品,否则等待。要求一个消费者进程从缓冲区连续取出10件产品后,其他消费者进程才可以取产品。请使用信号量 P, V ( wait(), signal())操作实现进程间的互斥与同步,要求写出完整的过程,并说明所用信号量的含义和初值。

问题分析

两个进程,生产者(Producer)和消费者(Costumer);两个资源信号量empty=100,代表一共有100个产品空位,full=0表示缓冲区中是否有产品,有的话则可以取走消费;两个互斥信号量mutex_1=1(表示只能有一个进程访问缓冲区),mutex_2=1(表示消费者进入缓冲区可以连续取10件产品,在连续取得过程中不能有其他进程的干扰),

代码如下:
 

//定义信号量 
   Semapher mutex=1,mutex_2=1;
   Semapher empty=100,full=0;
//生产者进程:
Producer()
{
  While(1)
  {
     P(empty);//判断缓冲区是否为空,空的话则生产产品
     P(mutex_1);//进入临界区生产
     生产产品;
     V(mutex_1);//离开临界区
     V(full);//非空数量+1
  }
}
//消费者进程
Costumer()
{
  While(1)
  {
     P(mutex_2);//阻止其他消费者进入
     for(i=0,i<10,i++)
    {
       P(full);//判断是否有产品可以取
       P(mutex_1);//进入临界区
        取产品;
       V(mutex_1);//离开临界资源
       V(empty);//空数+1
    }
       V(mutex_2);

   }
}

该生产者-消费者的问题暂时写这么多,大家一定要掌握啊!如有疑问,可以评论或私聊我哦。

其他两个经典的同步进程问题可以看我的其他文章,还有一篇单独关于真题的练习,大家可以看一下,同时小编也会给予详细的解析。

欢迎大家指正~~

Logo

鸿蒙生态一站式服务平台。

更多推荐