PV操作


一、PV操作

  PV操作是一種實現進程互斥與同步的有效方法。PV操作與信號量的處理相關。P(passeren)通過,理解為申請資源,V(vrijgeven)釋放,理解為釋放資源。

  PV操作是典型的同步機制之一。用一個信號量與一個消息聯系起來,當信號量的值為0時,表示期望的消息尚未產生;當信號量的值非0時,表示期望的消息已經存在。用PV操作實現進程同步時,調用P操作測試消息是否到達,調用V操作發送消息。

  PV操作,原來這是狄克斯特拉用荷蘭文定義的,因為在荷蘭文中,通過叫passeren,釋放叫vrijgeven,PV操作因此得名。這是在計算機術語中不是用英語表達的極少數的例子之一。

二、信號量

  信號量(semaphore)的概念和PV操作是荷蘭科學家E.W.Dijkstra提出來的。信號是鐵路交通管理中的一種常用設備,交通管理人員利用信號顏色的變化來實現交通管理。在操作系統中,信號量S是一整數。S大於或等於零,代表可供並發進程使用的資源實體數;在S小於零時,ISl表示正在等待使用資源實體的進程數。建立一個信號量必須說明此信號量所代表的意義並且賦初值。除賦初值外,信號量僅能通過PV操作來訪問。
  信號量按其用途可分為兩種:

  ①公用信號量。聯系一組並發進程,相關的進程均可在此信號量上執行P操作和V操作,初值常常為1,用於實現進程互斥。

  ②私有信號量。聯系一組並發進程,僅允許擁有此信號量的進程執行P操作,而其他相關進程可在其上施行V操作。初值常常為0或正整數,多用於實現進程同步。

  PV操作是由兩個操作,即P操作和V操作組成的。P操作和V操作是兩個在信號量上進行操作的過程,假定用S表示信號量,則把這兩個過程記作P(S)和V(S)。

三、PV操作原理

  用PV操作來管理共享資源時,首先要確保PV操作自身執行的正確性。由於P(S)和V(S)都是在同一個信號量S上操作,為了使得它們在執行時不發生因交叉訪問信號量S而可能出現的錯誤,約定P(S)和V(S)必須是兩個不可被中斷的過程,即讓它們在屏蔽中斷下執行。把不可被中斷的過程稱為原語。於是,P操作和V操作實際上應該是P操作原語和V操作原語。

  P操作的主要動作是:

  ①S減1;

  ②若S減1后仍大於或等於0,則進程繼續執行;

  ③若S減1后小於0,則該進程被阻塞后放入等待該信號量的等待隊列中,然后轉進程調度。

  V操作的主要動作是:

  ①S加1;

  ②若相加后結果大於0,則進程繼續執行;

  ③若相加后結果小於或等於0,則從該信號的等待隊列中釋放一個等待進程,然后再返回原進程繼續執行或轉進程調度。

  PV操作對於每一個進程來說,都只能進行一次,而且必須成對使用。在PV原語執行期間不允許有中斷發生。原語不能被中斷執行,因為原語對變量的操作過程如果被打斷,可能會去運行另一個對同一變量的操作過程,從而出現臨界段問題。如果能夠找到一種解決臨界段問題的元方法,就可以實現對共享變量操作的原子性。

四、進程的同步與互斥

1,進程同步

(1)調用P操作測試消息是否到達

  任何進程調用P操作可測試到自己所期望的消息是否已經到達。若消息尚未產生,則S=0,調用P(s)后,P(S)一定讓調用者成為等待信號量S的狀態,即調用者此時必定等待直到消息到達;若消息已經存在,則S≠0,調用P(S)后,進程不會成為等待狀態而可繼續執行,即進程測試到自己期望的消息已經存在。

(2)調用V操作發送消息

  任何進程要向其他進程發送消息時可調用V操作。若調用V操作之前S=0,表示消息尚未產生且無等待消息的進程,則調用V(S)后,V(s)執行S:=S+1使S≠0,即意味着消息已存在;若調用V操作之前S<0,表示消息未產生前已有進程在等待消息,則調用V(S)后將釋放一個等待消息者,即表示該進程等待的消息已經到達,可以繼續執行。

  在用PV操作實現同步時,一定要根據具體的問題來定義信號量和調用P操作或V操作。一個信號量與一個消息聯系在一起,當有多個消息時必須定義多個信號量;測試不同的消息是否到達或發送不同的消息時,應對不同的信號量調用P操作或V操作。

2,進程互斥

(1)設立一個互斥信號量S,表示臨界區,其取值為1,0,-1,…其中,S=1表示無並發進程進入S臨界區;S=0表示已有一個並發進程進入了S臨界區;S等於負數表示已有一個並發進程進入S臨界區,且有|S|個進程等待進入S臨界區,S的初值為1。

(2)用PV操作表示對S臨界區的申請和釋放。在進入臨界區之前,通過P操作進行申請,在退出臨界區之后,通過V操作釋放。

五、相關推論

推論1:若信號量S為正值,則該值等於在阻塞進程之前對信號量S可施行的P操作數,亦即等於S所代表的實際還可以使用的物理資源數。

推論2:若信號量s為負值,則其絕對值等於登記排列在該信號量S等待隊列之中的進程個數,亦即恰好等於對信號量S實施P操作而被阻塞並進入信號量S等待隊列的進程數。

推論3:通常,P操作意味着請求一個資源,V操作意味着釋放一個資源。在一定條件下,P操作代表阻塞進程操作,而V操作代表喚醒被阻塞進程的操作。

六、生產者消費者問題

P操作定義如下:

1.mutex減1。

2.若mutex>=0,則P操作返回,該線程可以”通過“並繼續執行。

3.若mutex<0,則該線程被阻塞,進入操作系統的阻塞隊列。

V操作定義如下:

1.mutex加1。

2.若mutex>0,則V操作返回,該線程繼續執行。

3.若mutex<=0,則從阻塞隊列中喚醒一個阻塞在該信號量上的線程,然后再返回原線程(調用V操作的線程)繼續執行。

核心思想:

1、該類問題需要注意對緩沖區大小為n的處理,當緩沖區中有空時,便可對 empty 變量執行 P 操作,一旦取走一個資源便可執行 V 操作以釋放空閑區。對 empty 和 full 變量的 P 操作 必須放在 mutex 的P操作之前。

2、P操作即wait操作表示進程請求一個資源,V操作即signal表示進程釋放一個資源,且信號量機制遵循了同步機制的“讓權等待”原則。

3、wait():當緩沖區已滿/空時,生產者或消費者線程停止自己的執行,釋放鎖,使自己處於等待狀態,讓其它線程執行。notify():當生產者或消費者向緩沖區放入或取出一個產品時,向其他等待的線程發出通知,同時釋放鎖,使自己處於等待狀態,讓其它線程執行。wait()、nofity()這兩個方法必須有鎖對象調用,而任意對象都可以作為 synchronized 的同步鎖。

4、使用synchronized修飾的方法,叫做同步方法,保證A線程執行該方法的時,其他線程只能在方法外等待。被final修飾的方法是一個最終方法,不能被重寫,重寫會報錯。

 1 import java.util.Scanner;  2 
 3 public class PV {  4 
 5     //信號量
 6     static class Semaphore {  7         public int value;  8         public Semaphore(int value) {  9             this.value = value;  10  }  11         //P操作(passeren,通過)
 12         public synchronized final void P() {  13             value--;  14             if (value < 0) {  15                 try {  16                     //當緩沖區已滿/空時,生產者/消費者線程停止自己的執行,釋放鎖,使自己處於等待狀態,讓其它線程執行
 17                     this.wait();  18                 } catch (InterruptedException e) {  19  e.printStackTrace();  20  }  21  }  22  }  23         //V操作(vrijgeven,釋放)
 24         public synchronized final void V() {  25             value++;  26             if (value <= 0) {  27                 //當生產者或消費者向緩沖區放入或取出一個產品時,向其他等待的線程發出通知,同時釋放鎖,使自己處於等待狀態,讓其它線程執行。
 28                 this.notify();  29  }  30  }  31  }  32 
 33     static class Global {  34         //空閑緩沖區初始化為3
 35         public static Semaphore empty = new Semaphore(3);  36         //滿緩沖區初始化為空
 37         public static Semaphore full = new Semaphore(0);  38         //臨界區互斥信號量
 39         public static Semaphore mutex = new Semaphore(1);  40         //count用於緩沖區中的進程進行計數
 41         public static int count = 0;  42         //定時等待
 43         public static void timingwait() {  44             try {  45                 Thread.sleep(2000);  46             } catch (InterruptedException e) {  47  e.printStackTrace();  48  }  49  }  50  }  51 
 52     //生產者
 53     class Producer implements Runnable {  54  @Override  55         public void run() {  56             String threadName = Thread.currentThread().getName();  57  Global.timingwait();  58             System.out.println(threadName + " 生產出一個商品...");  59             //獲取空緩沖區單元
 60  Global.empty.P();  61             //進入臨界區
 62  Global.mutex.P();  63  Global.timingwait();  64             System.out.println(threadName + " 將產品放入緩沖區--緩沖區剩余 " + (++Global.count) + " 個產品");  65             //離開臨界區,釋放信號量
 66  Global.mutex.V();  67             //滿緩沖區數加1
 68  Global.full.V();  69  }  70  }  71 
 72     //消費者
 73     class Consumer implements Runnable {  74  @Override  75         public void run() {  76             String threadName = Thread.currentThread().getName();  77  Global.timingwait();  78             //獲取滿緩沖區單元
 79  Global.full.P();  80             //進入臨界區
 81  Global.mutex.P();  82  Global.timingwait();  83             System.out.println(threadName + " 從緩沖區取出一個產品--緩沖區剩余 " + (--Global.count) + " 個產品");  84             //離開臨界區,釋放互斥信號量
 85  Global.mutex.V();  86             //空緩沖區加1
 87  Global.empty.V();  88             System.out.println(threadName + " 消費一個商品...");  89  }  90  }  91 
 92     public static void main(String[] args) {  93         int producer, consumer;  94         Scanner sc = new Scanner(System.in);  95         System.out.print("請輸入生產者數目:");  96         producer = sc.nextInt();  97         System.out.print("請輸入消費者數目:");  98         consumer = sc.nextInt();  99         for (int i = 0; i < producer; i++) { 100             new Thread(new PV().new Producer(), "生產者" + i + "號").start(); 101  } 102         for (int i = 0; i < consumer; i++) { 103             new Thread(new PV().new Consumer(), "消費者" + i + "號").start(); 104  } 105  } 106 }

執行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM