[进程同步]—生产者与消费者问题

207 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

 生产者与消费者问题

  • PV操作是用来操作信号量的。

    • P:等待——wait——减法作用——阻塞作用

    • V:释放——signal——加法作用——唤醒作用

    • S.value > 0 :有空闲CPU;

      S.value = 0:CPU刚好用完;

      S.value < 0:进程等待;

      • P操作
      void wait(S)
      {
          S.value--;
          if (S.value < 0)
          {
              加入阻塞队列;
          }
      }
      
      • V操作
      void signal(S)
      {
          S.value++;
          if (S.value <= 0)
          {
              唤醒阻塞队列第一个进程;
          }
      }
      
  • 解题思路:

    1.画图理解题目
    2.判断题目类型
    3.分析进程数目,填写进程模板
    4.补充基本代码
    5.补充P,V代码
    6.调整代码
    
  • 例:爸爸往桌子上每次放一个苹果,儿子每次从桌子上拿一个苹果,放苹果和拿苹果不能同时进行,桌子上最多放10个苹果,用PV操作实现同步互斥。

    • 分析:爸爸——生产者——剩余空间(empty) = 10

      ​ 儿子——消费者——已占用空间(full) = 0

      ​ 信号量S = 1,用来实现互斥。

    • 特征:①容器 ≤ 容量

      ​ ②生产 消费

    • 伪代码

    Dad()
    {
        while(1)
        {
            P(empty);//判断盘子是否已满
            P(S);
            放苹果;
            V(S);
            V(full);//对已占用空间+1
        }
    }
    

    Son()
    {
        while()
        {
            P(full);//判断盘子是否为空
            P(S);
            取苹果;
            V(S);
            V(empty);//对盘子剩余空间+1
        }
    }
    

  • 例:桌子上有个盘子,每次只能放一个水果,妈妈放橘子,爸爸放苹果,儿子吃橘子,女儿吃苹果。盘子为空,爸爸或妈妈才能放水果,盘子有水果时,儿子和女儿才能取水果。

    • 分析:

image.png

​ 初始值:orange = 0,apple = 0,plate = 1,S = 1

  • 伪代码
        Mom()
        {
            while(1)
            {
                P(plate);
                P(S);
                放橘子;
                V(S);
                V(orange);
            }
        }
        Dad()
        {
            while(1)
            {
                P(plate);
                P(S);
                放苹果;
                V(S);
                V(apple);
            }
        }
        Son()
        {
            while(1)
            {
                P(orange);
                P(S);
                取橘子;
                V(S);
                V(plate);
            }
        }
        Daughter()
        {
            while(1)
            {
                P(apple);
                P(S);
                取苹果;
                V(S);
                V(plate);
            }
        }
  • 操作同一个对象的时候,使用信号量S来实现互斥。
  • [2015—408统考]

    • 有A,B两个人通过信箱辩论,每个人都从自己的信箱取得对方的问题,将答案和新问题组成一个邮件放入对方的信箱中。假设A的信箱可装M封邮件,B的信箱可装N封邮件。初始时A信箱有X封,B信箱有Y封,,辩论者每次只取一封邮件。请用P,V操作实现,并解释信号量的初始值和含义。

      • 分析:生产者A——B的剩余空间

        ​ 生产者B——A的剩余空间

        ​ 消费者A——自己邮箱还有多少封信

        ​ 消费者B——自己邮箱还有多少封信

        full-A:A信箱有多少封邮件

        empty-A:A信箱的容量

        full-B:B信箱有多少封邮件

        empty-B:B信箱的容量

        mutex-A:A信箱的信号量

        mutex-B:B信箱的信号量

      • 初始值:mutex-A = 1,mutex-B = 1

        full-A = x , empty-A = M - X

        full-B = y, empty-B = N - y

      A()
      {
          while(1)
          P(full-A);
          P(mutex-A);
          从自己邮箱取信;
          V(mutex-A);
          V(empty-A);
          读信;
          P(empty-B);
          P(mutex-B);
          向B邮箱投信;
          V(mutex-B);
          V(full-B);
      }
      
      B()
      {
          while(1)
          P(full-B);
          P(mutex-B);
          从自己邮箱取信;
          V(mutex-B);
          V(empty-B);
          读信;
          P(empty-A);
          P(mutex-A);
          向A邮箱投信;
          V(mutex-A);
          V(full-A);
      }
      
  • [2014—408统考]

    • 例:系统中有多个生产者和消费者,共享一个能存放1000件产品的环形缓冲区(初始为空)。当缓冲区未满时生产者可放入生产的一个产品,否则等待。当缓冲区未空时,消费者进程可取走一件产品,否则等待。要求一个消费者从缓冲区连续取10件产品后,其他消费者才能取走产品。请用P,V操作实现该流程并解释信号量含义。

image.png

  • 分析:生产者(j)—剩余空间

生产者(i)—剩余空间

消费者(m)—物件数量

消费者(n)—物件数量

  • 初始值:empty = 1000;

full = 0;

mutex = 1;

mutex1 = 1;

        j()
        {
            while(1)
            {
                P(empty);
                P(mutex);
                放一件产品;
                V(mutex);
                V(full);
            }
        }
        i()
        {
            while(1)
            {
                P(empty);
                P(mutex);
                放一件产品;
                V(mutex);
                V(full);
            }
        }
        m()
        {
            while(1)
            {
                P(mutex1);
                for(int i = 0;i < 10;i++)
                {
                    P(full);
                    P(mutex);
                    取一件物品;
                    V(mutex);
                    V(empty);
                }
                V(mutex1);
            }
        }
        n()
        {
            while()
            {
                P(mutex1);
                for(int i = 0;i < 10;i++)
                {
                    P(full);
                    P(mutex);
                    取一件物品;
                    V(mutex);
                    V(empty);
                }
                V(mutex1);
            }
        }
  • 上述代码中,mnij的代码一样,所以合并mnij