PV原語經過操做信號量來處理進程間的同步與互斥的問題。其核心就是一段不可分割不可中斷的程序。html
關於信號量,其基本思路是 用一種新的變量類型(semaphore)來記錄當前的可用資源的數量。數據結構
a. semaphore的取值必須大於或等於0. 0表示當前已沒有空閒資源,而正數表示當前空閒資源的數量。併發
b. semaphore的取值可正可負, 負數的絕對值表示正在等待進入臨界區的進程個數。工具
2. 信號量是由操做系統來維護的,用戶進程只能經過初始化和兩個標準原語(P、V原語)來訪問。初始化可指定一個非負整數,即空閒資源總數。測試
3. P原語:P是荷蘭語Proberen(測試)的首字母。爲阻塞原語,負責把當前進程由運行狀態轉換爲阻塞狀態,直到另一個進程喚醒它。操做爲:申請一個空閒資源(把信號量減1),若成功,則退出;若失敗,則該進程被阻塞;ui
V原語:V是荷蘭語Verhogen(增長)的首字母。爲喚醒原語,負責把一個被阻塞的進程喚醒,它有一個參數表,存放着等待被喚醒的進程信息。操做爲:釋放一個被佔用的資源(把信號量加1),若是發現有被阻塞的進程,則選擇一個喚醒之。spa
P原語操做的動做是: 操作系統
(1)sem減1; .net
(2)若sem減1後仍大於或等於零,則進程繼續執行; unix
(3)若sem減1後小於零,則該進程被阻塞後進入與該信號相對應的隊列中,而後轉進程調度。
V原語操做的動做是:
(1)sem加1;
(2)若相加結果大於零,則進程繼續執行; (
(3)若相加結果小於或等於零,則從該信號的等待隊列中喚醒一等待進程,而後再返回原進程繼續執行或轉進程調度。
PV操做對於每個進程來講,都只能進行一次,並且必須成對使用。在PV原語執行期間不容許有中斷的發生。
4. 具體PV原語對信號量的操做能夠分爲三種狀況:
1) 把信號量視爲一個加鎖標誌位,實現對一個共享變量的互斥訪問。
實現過程:
P(mutex); // 設mutex爲互斥信號量 mutex的初始值爲1 訪問該共享數據
V (mutex);
非臨界區
2) 把信號量視爲是某種類型的共享資源的剩餘個數 實現對一類共享資源的訪問。
P(resource); // resource的初始值爲該資源的個數N 使用該資源;
V(resource);
非臨界區
3) 把信號量做爲進程間的同步工具
實現過程:
臨界區C1;
P(S);
V(S);
臨界區C2;
附: (S):①將信號量S的值減1,即S=S-1;
②若是S>=0,則該進程繼續執行;不然該進程置爲等待狀態,排入等待隊列。
V(S):①將信號量S的值加1,即S=S+1;
②若是S>0,則該進程繼續執行;不然釋放隊列中第一個等待信號量的進程。
什麼是信號量?信號量(semaphore)的數據結構爲一個值和一個指針,指針指向等待該信號量的下一個進程。信號
量的值與相應資源的使用狀況有關。當它的值大於0時,表示當前可用資源的數量;當它的值小於0時,其絕對值表示等待使用該資
源的進程個數。注意,信號量的值僅能由PV操做來改變。
通常來講,信號量S>=0時,S表示可用資源的數量。執行一次P操做意味着請求分配一個單位資源,所以S的值減1;當S<0時,表示已經沒有可用資源,請求者必須等待別的進程釋放該類資源,它才能運行下去。而執行一個V操做意味着釋放一個單位資源,所以S的值加1;若S£0,表示有某些進程正在等待該資源,所以要喚醒一個等待狀態的進程,使之運行下去。
----------------------------------------------------------------------------------------------------------------------------
例1:桌子上有一個水果盤,每一次能夠往裏面放入一個水果。爸爸專向盤子中放蘋果,兒子專等吃盤子中的蘋果。把爸爸、兒子看做二個進程,試用P、V操做使這兩個進程能正確地併發執行。
分析:爸爸和兒子兩個進程相互制約,爸爸進程執行完即往盤中放入蘋果後,兒子進程才能執行即吃蘋果。所以該問題爲進程間的同步問題。
解:
semaphore S_PlateNum; // 盤子容量,初值爲1
semaphore S_AppleNum; // 蘋果數量,初值爲0
void father( ) // 父親進程 {
while(1){
P(S_PlateNum);
往盤子中放入一個蘋果;
V(S_AppleNum);
}
}
void son( ) // 兒子進程 {
while(1){
P(S_AppleNum);
從盤中取出蘋果;
V(S_PlateNum);
吃蘋果;
}
}
---其餘:
1. pv原語操做詳解
2. 信號量與PV原語操做