PV操作和信號量

1.信號量的類型定義
信號量(semaphore)的數據結構爲一個值和一個指針,指針指向等待該信號量的下一個進程。信號量的值與相應資源的使用情況有關。當它的值大於0時,表示當前可用資源的數量;當它的值小於0時,其絕對值表示等待使用該資源的進程個數。注意,信號量的值僅能由PV操作來改變。

一般來說,信號量S>=0時,S表示可用資源的數量。執行一次P操作意味着請求分配一個單位資源,因此S的值減1;當S<0時,表示已經沒有可用資源,請求者必須等待別的進程釋放該類資源,它才能運行下去。而執行一個V操作意味着釋放一個單位資源,因此S的值加1;若S<0,表示有某些進程正在等待該資源,因此要喚醒一個等待狀態的進程,使之運行下去。


2.PV原語
PV操作是典型的同步機制之一。用一個信號量與一個消 息聯繫起來,當信 號量的值爲0時,表示期 望的消息尚未產生;當信號 量的值非0時,表示期望的消息已經存在。用P V操作實現進程同步時,調用P操作測試消息是否到達,調用V操作發送消息。
對一個信號量變量可以進行兩種原語操作:p操作和v操作,定義如下:procedure p(var s:samephore);
{
s.value=s.value-1;
if (s.value<0) asleep(s.queue);
}
procedure v(var s:samephore);
{
s.value=s.value+1;
if (s.value<=0) wakeup(s.queue);
}
其中用到兩個標準過程:
asleep(s.queue);執行此操作的進程的PCB進入s.queue尾部,進程變成等待狀態
wakeup(s.queue);將s.queue頭進程喚醒插入就緒隊列
s.value初值爲1時,可以用來實現進程的互斥。


3、同步和互斥的概念

互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。

同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問,更強調進程間的協作,如同生產者消費者問題。


4、利用信號量和PV原語進行同步和互斥

利用信號量和PV操作實現進程互斥的一般模型是:
進程P1 進程P2 …… 進程Pn
……  ……  ……
P(S);  P(S);  P(S);
臨界區;  臨界區;  臨界區;
V(S);  V(S);  V(S);
……  ……  …… ……
其中信號量S用於互斥,初值爲1。
使用PV操作實現進程互斥時應該注意的是:
⑴每個程序中用戶實現互斥的P、V操作必須成對出現,先做P操作,進臨界區,後做V操作,出臨界區。若有多個分支,要認真檢查其成對性。
⑵P、V操作應分別緊靠臨界區的頭尾部,臨界區的代碼應儘可能短,不能有死循環。
⑶互斥信號量的初值一般爲1。

利用信號量和PV操作實現進程同步:
PV操作是典型的同步機制之一。用一個信號量與一個消息聯繫起來,當信號量的值爲0時,表示期望的消息尚未產生;當信號量的值非0時,表示期望的消息已經存在。用PV操作實現進程同步時,調用P操作測試消息是否到達,調用V操作發送消息。
使用PV操作實現進程同步時應該注意的是:
⑴分析進程間的制約關係,確定信號量種類。在保持進程間有正確的同步關係情況下,哪個進程先執行,哪些進程後執行,彼此間通過什麼資源(信號量)進行協調,從而明確要設置哪些信號量。
⑵信號量的初值與相應資源的數量有關,也與P、V操作在程序代碼中出現的位置有關。
⑶同一信號量的P、V操作要成對出現,但它們分別在不同的進程代碼中。


5、典型理解偏差
三個問題:
一,以V原語的1、2步來做,Sem不就永遠大於0,那進程不就一直循環執行成爲死循環了?
二,Sem大於0那就表示有臨界資源可供使用,爲什麼不喚醒進程?
三,Sem小於0應該是說沒有臨界資源可供使用,爲什麼還要喚醒進程?
析疑:
一,P操作對sem減1的。P、V原語必須成對使用!從而不會造成死循環。
二,Sem大於0的確表示有臨界資源可供使用,而且這個時候沒有進程被阻塞在這個資源上,也就是說沒有進程因爲得不到這類資源而阻塞,所以沒有被阻塞的進程,自然不需要喚醒。
三,V原語操作的本質在於:一個進程使用完臨界資源後,釋放臨界資源,使Sem加1,以通知其它的進程,這個時候如果Sem<0,表明有進程阻塞在該類資源上,因此要從阻塞隊列裏喚醒一個進程來“轉手”該類資源。比如,有兩個某類資源,四個進程A、B、C、D要用該類資源,最開始Sem=2,當A進入,Sem=1,當B進入Sem=0,表明該類資源剛好用完, 當C進入時Sem=-1,表明有一個進程被阻塞了,D進入,Sem=-2。當A用完該類資源時,進行V操作,Sem=-1,釋放該類資源,而這時Sem<0,表明有進程阻塞在該類資源上,於是喚醒一個。
爲了進一步加深理解,再引入二個問題:
四,如果是互斥信號量的話,應該設置信號量Sem=1,但是當有5個進程都訪問的話,最後在該信號量的鏈表裏會有4個在等待,也是說S=-4,那麼第一個進程執行了V操作使S加1,釋放了資源,下一個應該能夠執行,但喚醒的這個進程在執行P操作時因S〈0,也還是執行不了,這是怎麼回事呢?
五,Sem的絕對值表示等待的進程數,同時又表示臨界資源,這到底是怎麼回事?
析疑:
四,當一個進程阻塞了的時候,它已經執行過了P操作,並卡在臨界區那個地方。當喚醒它時就立即進入它自己的臨界區,並不需要執行P操作了,當執行完了臨界區的程序後,就執行V操作。
五,當信號量Sem小於0時,其絕對值表示系統中因請求該類資源而被阻塞的進程數目.S大於0時表示可用的臨界資源數。注意在不同情況下所表達的含義不一樣。當等於0時,表示剛好用完。


6、應用題

【例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 S=1;
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);
              吃蘋果;
            }

 
思考題:


四個進程A、B、C、D都要讀一個共享文件F,系統允許多個進程同時讀文件F。但限制是進程A和進程C不能同時讀文件F,進程B和進程D也不能同時讀文件F。爲了使這四個進程併發執行時能按系統要求使用文件,現用PV操作進行管理,請回答下面的問題:
    (1)應定義的信號量及初值:                    。
    (2)在下列的程序中填上適當的P、V操作,以保證它們能正確併發工作:
     A()                B()                  C()                 D()
      {                 {                    {                  {
      [1];                [3];                  [5];                 [7];
      read F;             read F;                read F;              read F;
     [2];                [4];                  [6];                 [8];
      }                  }                    }                  } 


    思考題解答:
(1)定義二個信號量S1、S2,初值均爲1,即:S1=1,S2=1。其中進程A和C使用信號量S1,進程B和D使用信號量S2。
(2)從[1]到[8]分別爲:P(S1) V(S1) P(S2) V(S2) P(S1) V(S1) P(S2) V(S2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章