zoukankan      html  css  js  c++  java
  • PV操作

    PV操作的含义  

      PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:
         P(S):①将信号量S的值减1,即S=S-1;
                      ②如果S>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
            V(S):①将信号量S的值加1,即S=S+1;
                      ②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
    PV操作的意义
    :我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

    什么是信号量?

      信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。
         一般来说,信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S<=0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。

    利用信号量和PV操作实现进程互斥的一般模型是:
      进程P1              进程P2           ……          进程Pn
      ……                  ……                           ……
      P(S);              P(S);                         P(S);

      临界区;             临界区;                        临界区;
      V(S);              V(S);                        V(S);
      ……                  ……            ……           ……

        其中信号量S用于互斥,初值为1。

     临界区:就是进程访问临界资源的那段代码。

        使用PV操作实现进程互斥时应该注意的是:
        (1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
        (2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
        (3)互斥信号量的初值一般为1。

    利用信号量和PV操作实现进程同步

      下面是一张同步的图:

      

      这张图也特别的形象具体,我们具体来看看这张图,A仓库有货物,然后我们需要把货物搬运到B仓库,由搬运工甲和搬运工乙来完成这个过程;那么他们的目标就只有一个,就是把货物从A搬到B去,共同奔着这个方向去发展,所以我们说这是一个同步的问题。

      PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
           使用PV操作实现进程同步时应该注意的是:

          (1)分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。
          (2)信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。
          (3)同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。

    示例

    【例1】生产者-消费者问题

      在多道程序环境下,进程同步是一个十分重要又令人感兴趣的问题,而生产者-消费者问题是其中一个有代表性的进程同步问题。下面我们给出了各种情况下的生产者-消费者问题,深入地分析和透彻地理解这个例子,对于全面解决操作系统内的同步、互斥问题将有很大帮助。

      (1)一个生产者,一个消费者,公用一个缓冲区。
        定义两个同步信号量:
          empty——表示缓冲区是否为空,初值为1
            full——表示缓冲区中是否为满,初值为0。
        生产者进程
          while(TRUE){
            生产一个产品;
                 P(empty);
                 产品送往Buffer;
                 V(full);
          }

        消费者进程
          while(True){
            P(full);

              从Buffer取出一个产品;
              V(empty);
              消费该产品;
            }
       (2)一个生产者,一个消费者,公用n个环形缓冲区。
        定义两个同步信号量:
          empty——表示缓冲区是否为空,初值为n。
          full——表示缓冲区中是否为满,初值为0。

         设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指,指向下一个可用的缓冲区。

      生产者进程
        while(TRUE){
             生产一个产品;
             P(empty);
             产品送往buffer(in);
             in=(in+1)mod n
             V(full);
      }

      消费者进程
        while(TRUE){
          P(full);
            从buffer(out)中取出产品;
            out=(out+1)mod n
            V(empty);
           消费该产品;
            }
         (3)一组生产者,一组消费者,公用n个环形缓冲区
         在这个问题中,不仅生产者与消费者之间要同步,而且各个生产者之间、各个消费者之间还必须互斥地访问缓冲区。

      定义四个信号量:
        empty——表示缓冲区是否为空,初值为n。
        full——表示缓冲区中是否为满,初值为0。
        mutex1——生产者之间的互斥信号量,初值为1。
        mutex2——消费者之间的互斥信号量,初值为1。  

           设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。
      生产者进程
        while(TRUE){
             生产一个产品;
             P(empty);
             P(mutex1)
             产品送往buffer(in);
             in=(in+1)mod n
             V(mutex1);
             V(full);
        }

      消费者进程
        while(TRUE){

         P(full)
           P(mutex2)

           从buffer(out)中取出产品;
           out=(out+1)mod n
           V(mutex2);
           V(empty);
           消费该产品;
           }
        需要注意的是无论在生产者进程中还是在消费者进程中,两个P操作的次序不能颠倒。应先执行同步信号量的P操作,然后再执行互斥信号量的P操作,否则可能造成进程死锁。

     

    【例2】桌上有一空盘,允许存放一只水果。爸爸可向盘中放苹果,也可向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发进程的同步。

    分析 在本题中,爸爸、儿子、女儿共用一个盘子,盘中一次只能放一个水果。当盘子为空时,爸爸可将一个水果放入果盘中。若放入果盘中的是桔子,则允许儿子吃,女儿必须等待;若放入果盘中的是苹果,则允许女儿吃,儿子必须等待。本题实际上是生产者-消费者问题的一种变形。这里,生产者放入缓冲区的产品有两类,消费者也有两类,每类消费者只消费其中固定的一类产品。

     

        :在本题中,应设置三个信号量S、So、Sa,信号量S表示盘子是否为空,其初值为l;信号量So表示盘中是否有桔子,其初值为0;信号量Sa表示盘中是否有苹果,其初值为0。同步描述如下:
    int S1;
    int Sa=
    0;
    int So=0;

          main()
          {
            cobegin
                father();      /*父亲进程*/
                son();        /*儿子进程*/
                daughter();    /*女儿进程*/
            coend
       
        father()
        {
            while(1)
              {
                P(S);
                将水果放入盘中;
                if(放入的是桔子)V(So);
                else  V(Sa);
               }
         }
        son()
        {
            while(1)
              {
                 P(So);
                 从盘中取出桔子;
                 V(S);
                 吃桔子;
               
        }
        daughter()
        {
             while(1)
             {
                  P(Sa);
                  从盘中取出苹果;
                  V(S);
                  吃苹果;
               

     

  • 相关阅读:
    .NET XmlNavigator with Namespace
    编程要素
    【FOJ】1962 新击鼓传花游戏
    【POJ】1389 Area of Simple Polygons
    【POJ】2482 Stars in Your Window
    【HDU】3265 Posters
    【HDU】1199 Color the Ball
    【HDU】3642 Get The Treasury
    【HDU】4027 Can you answer these queries?
    【HDU】1542 Atlantis
  • 原文地址:https://www.cnblogs.com/ktao/p/7819899.html
Copyright © 2011-2022 走看看