1965年,荷蘭學者Djikstra提出信號量(Semaphores)機制是一種卓有成效的進程同步工具。在長期的應用中,信號量機制又獲得了很大的發展,從整型信號量記錄型信號量,進而發展成“信號量集”機制,下面我們來討論一下各種信號量機制的內容。
1、整形信號量(經典的PV操作:P(wait):申請資源 V(signal):釋放資源)
1 wait(S):while S<=0 do no-op; 2 S:=S-1; 3 signal(S): S:=S+1
2、記錄型信號量
在整形信號量機制中的wait操作,只要是信號量S≤0,就會不斷測試。該機制並未遵守“讓權等待”的准則,而是使進程處於“忙等”的狀態。
在記錄型信號量是一種不存在“忙等”現象的進程同步機制。但是采取了“讓權等待”的策略后又會出現多個進程等待訪問同一臨界資源的情況。為此,在信號量機制中出了一個需要用於表示資源數目的整形變量value外,還應增加一個進程鏈表指針L,用於鏈接上述所有等待進程。
1 type semapthere = record // 信號量類型 記錄型 2 value:integer; // 資源數目 3 L:list of process // 進程鏈表指針 4 end 5 P、V操作如下: 6 procedure wait(S) 7 var S:semapthere; // 聲明一個記錄型信號量 包含value和L 8 begin 9 S.value:=S.value-1 // 申請一個資源,資源數目少一個 10 if S.value<0 then block(S.L); // 如果資源數目小於0,說明該類資源分配完畢,調用block原語,進行自我阻塞,放棄處理機。然后將當前進程插入到信號量鏈表中,此時S.value的絕對值表示該信號量鏈表中阻塞進程的數目。 11 end 12 procedure signal(S) 13 var S:semapthere; 14 begin 15 S.value:=S.value+1; // 釋放一個單位資源,資源數目加1 16 if S.value<=0 then wakeup(S.L); // 如果資源數目小於0(加1后),表示仍然有進程處於阻塞狀態,調用wakeup原語將S.L中第一個等待的進程喚醒。 17 end
3、AND型信號量
前面討論的進程互斥問題都是共享一個臨界資源而言的,但是在很多情況下一個進程需要獲得兩個或多個共享資源后才能執行其任務。如果此類問題利用上述辦法將會陷入死鎖狀態。
AND同步機制的基本思想:將進程在整個運行過程中需要的所有資源一次性全部分配給進程,待進程用完后再一起釋放。只要尚有一個資源未分配給進程,其他所有可能為之分配的資源也不分配給它。亦即,對若干個臨界資源的分配采取原子操作方式:要么把它所請求的資源全部分配給進程,要么一個也不分配。由死鎖理論可知,可避免死鎖的發生。
1 Swait(S1,S2,...,Sn) 2 if Si>=1 and ... and Sn>=1 then 3 for i:=1 to n do 4 Si:=Si-1; 5 endfor 6 else 7 place the process in the waiting queue associated with the first Si found with Si<1,and set the program count of this process to the begining of Swait operation 8 endif 9 Ssignal(S1,S2,...,Sn) 10 for i:=1 to n do 11 Si = Si+1; 12 Remove all the process waiting in the queue associated with Si into the ready queue. 13 endfor;
4、信號量集:
在記錄性信號量機制中,wait(S)或signal(S)操作僅能對信號量施以加1或減1操作,意味着每次只能獲得或釋放一個單位的臨界資源。而當一次需要N個某類臨界資源時便需要進行N次操作,顯然這是低效的。此外在一些情況下,當資源數量低於某一下限值時,便不予以分配。因而在每次分配之前,都必須測試該資源的數目,看其是否大於其下限值。基於以上兩點,對AND型信號量加以擴充,行成一般化的“信號量集”機制。
Swait操作描述如下:
S:信號量 d:需求值 t:下限值
1 Swait(S1,t1,d1,...,Sn,tn,dn) 2 if S1>=t1 and ... and Sn >- tn then // 每種信號量大於下限值 3 for i:=1 to n do 4 Si:=Si - di; // 分配進程所需求的資源(信號量減去相應的需求值為剩余信號量的數量) 5 endfor 6 else 7 Place the executing process in the waiting queue of the first Si with Si<ti and set its program counter to the begining of the Swait operation. 8 endif 9 Ssignal(S1,d1,...,Sn,dn) 10 for i:=1 to n do 11 Si:=Si+di; // 釋放資源 12 Remove all the process waiting in the queue associated with Si into the ready queue 13 endfor
下面討論一般“信號量集”的幾種特殊的情況:
(1)Swait(S,d,d):此時信號量集中只有一個信號量S,但允許每次申請d個資源,當現有資源少於d時,不予分配
(2)Swait(S,d,d):此時信號量集已退化為一般的記錄型信號量(S>1)或互斥信號量(S=1時)
(3)Swait(S,1,0):這是一種很特殊且很有用的信號量操作。當S≥1時,允許多個進程進入某特定區;當S變為0后將阻止任何進程進入特定區,換言之,它相當於一個可控開關。