本篇文章,講解了PV操作的作用,舉了兩個情景模擬pv操作的應用原理,同時講解了PV操作涉及到的基本概念,並且在文章的最後用僞代碼寫了pv操作過程。
要理解PV操作,請先看兩個場景:
場景1:飛機場售票窗口進程
Process Pi(i=1,2,3,…,n)
Begin
查找當天機票剩餘量A
If A>1 then
A=A-1;
售出一張票
Else 輸出票以售完
End
若同時有5個窗口執行該程序,如果5個程序同時併發執行,同時取到相同的票數(實際情況中:用鎖就能解決該問題,不會取到相同的票數,此處只是爲說明pv操作),則售了5張票,而實際票數只減了1張。
場景2:進程A向緩存中寫數據(緩存只存一條數據),進程B從緩存存數據。如果在B未取走數據前就寫入數據,數據會被覆蓋;若A還沒寫入新數據前B寫入一次數據,則會讀取到舊數據,怎麼保證兩個進程能夠同步執行?
情景一爲互斥問題,當一個進程讀取並修改數據的時候,另一個進程不能讀取數據;情景二爲同步問題,只有在進程A寫入數據後,B才能讀數據,否則可能讀到空數據或者重複數據;B讀取完,A才能寫入數據,否則可能數據還沒有讀的時候就被覆蓋掉。
使用PV操作可以解決上面的兩個問題,pv操作通過觀察信號量,從而控制多個進程間同步或互斥使用資源。
理解PV操作需要理解幾個重要的概念:臨界區,P操作,V操作,同步和互斥。
進程的互斥:若干個進程都要訪問某一共享資源時,任何時刻最多隻允許一個進程使用該資源,其他要使用該資源的進程必須等待,知道該資源的佔用者釋放進程。
進程的同步:併發進程間存在一種制約關係,一個進程的執行依賴另一個進程的消息,當一個進程沒有得到另一個進程的消息時等待,知道消息到達才被喚醒。
臨界區:當N個進程都要訪問同一個變量時,我們把與共享變量有關的程序段成爲臨界區。所有涉及該變量的臨界區成爲相關臨界區。
信號量:表示臨界區的進程是否可以往下執行,用S signal 代表信號量 ,s>0,代表當前變量或資源可以使用,該進程可以執行;S=0,表示當前無資源,當前進程不可往下執行;s<0表示當前有等待使用資源的進程,並且該負數的絕對值代表等待資源的進程數
p操作:判斷調用P操作的進程是否可以獲得資源並往下執行,如果信號量減一後大於0,將會往下執行,否則繼承進入等待隊列;
用代碼表示:
Procedure P(Var S:Semaphore);
Begin
s=s-1;
If s<0 then W(s);
End;{P}
V操作:進程釋放一個變量或資源,信號量加一,若等待隊列有進程,則釋放一個等待進程(該進程獲取資源並執行)
Procedure V(Var S:Semaphore);
Begin
s=s+1
if S<=0 then r(s)
end
那麼瞭解了PV操作和相關的概念後,我們可以試着用PV操作解決文章開始的兩個場景了:
解決場景一:將PV操作將如到場景一的僞代碼中
Begin
S:semaphore //定義信號量
S=1;
Process Pi(i=1,2,3,…,n)
Begin
查找當天機票剩餘量A
P(S); //進行P操作,當前的信號量減1大於等於0,則繼續進行,否則等待資源
If A>1 then
A=A-1;
V(S) //將當前變量或資源釋放,將信號量加一,結果如果小於等於0,則喚醒一個進程
售出一張票
Else 輸出票以售完
End
End
那麼此時,由於將信號量設置爲1,只能有一個進程訪問並修改機票數量,因此不會出現問題。
有此可見,當信號量爲正時,信號量的數值代表有幾個可用資源,爲0時,表示當前沒有可用資源,爲負值時說明當前有進程在等待資源。
解決場景二:
Begin
Buffer:integer
SA,SB:semaphore;
SA=1,SB=0;//定義A進程的信號量和B進程的信號量
Process A
Begin
L1: 向緩存中寫入一個數據Data;
P(SA); //進行P操作,判斷當前進程A是否可以向緩存寫入數據
Buffer=Data;
V(SB); //A進程寫入說後,將B進程的信號量加一,告訴B進程可以進行讀數據了
Goto L1;
End ;
Process B
Begin
L2: P(SB); //進行P操作,判斷當前進程B是否可以從緩存讀數據
從緩存取出一個數據Data;
V(SA); //讀完數據後,將A進程的信號量加一,告訴A進程可以寫入數據了
用取出的數據進行計算;
Goto L2;
End
End
PV操作解決了多個進程間共享數據和資源時,誤操作的問題,保證了安全的共享資源。