pv原語的含義
p操作和v操作是不可中斷的程式段,稱為原語。pv原語及訊號量的概念都是由荷蘭科學家e.w.dijkstra提出的。訊號量sem是一整數,sem大於等於零時代表可供併發程序使用的資源實體數,但sem小於零時則表示正在等待使用臨界區的程序數。
p原語操作的動作是:
(1)sem減1;
(2)若sem減1後仍大於或等於零,則程序繼續執行;
(3)若sem減1後小於零,則該程序被阻塞後進入與該訊號相對應的佇列中,然後轉程序排程。
v原語操作的動作是:
(1)sem加1;
(2)若相加結果大於零,則程序繼續執行;
(3)若相加結果小於或等於零,則從該訊號的等待佇列中喚醒一等待程序,然後再返回原程序繼續執行或轉程序排程。
pv操作對於每乙個程序來說,都只能進行一次,而且必須成對使用。在pv原語執行期間不允許有中斷的發生。
用pv原語實現程序的互斥
由於用於互斥的訊號量sem與所有的併發程序有關,所以稱之為公有訊號量。公有訊號量的值反映了公有資源的數量。只要把臨界區置於p(sem)和v(sem)之間,即可實現程序間的互斥。就象火車中的每節車廂只有乙個衛生間,該車廂的所有旅客共享這個公有資源:衛生間,所以旅客間必須互斥進入衛生間,只要把衛生間放在p(sem)和v(sem)之間,就可以到達互斥的效果。以下例子說明程序的互斥實現。
例1
生產圍棋的工人不小心把相等數量的黑子和白子混裝載乙個箱子裡,現要用自動分揀系統把黑子和白子分開,該系統由兩個併發執行的程序組成,功能如下:
(1)程序a專門揀黑子,程序b專門揀白子;
(2)每個程序每次只揀乙個子,當乙個程序在揀子時不允許另乙個程序去揀子;
分析:
第一步:確定程序間的關係。由功能(2)可知程序之間是互斥的關係。
第二步:確定訊號量及其值。由於程序a和程序b要互斥進入箱子去揀棋子,箱子是兩個程序的公有資源,所以設定乙個訊號量s,其值取決於公有資源的數目,由於箱子只有乙個,s的初值就設為1。
實現:
begin
s:semaphore;
s:=1;
cobegin
process a
begin
l1: p(s);
揀黑子;
v(s);
goto l1;
end;
process b
begin
l2:p(s);
揀白子;
v(s);
goto l2;
end;
coend;
end;
判斷程序間是否互斥,關鍵是看程序間是否共享某一公有資源,乙個公有資源與乙個訊號量相對應。確定訊號量的值是乙個關鍵點,它代表了可用資源實體數。如下例項:
例2
某車站售票廳,任何時刻最多可容納20名購票者進入,當售票廳中少於20名購票者時,廳外的購票者可立即進入,否則需要在外面等待。每個購票者可看成乙個程序。
分析:第一步:確定程序間的關係。售票廳是各程序共享的公有資源,當售票廳中多於20名購票者時,廳外的購票者需要在外面等待。所以程序間是互斥的關係。第二步:確定訊號量及其值。只有乙個公有資源:售票廳,所以設定乙個訊號量s。售票廳最多容納20個程序,即可用資源實體數為20,s的初值就設為20。
實現:
begin
s:semaphore;
s:=20;
cobegin
process pi(i=1,2,……)
begin p(s);
進入售票廳;
購票;退出;
v(s);
end;
coend
當購票者進入售票廳前要執行p(s)操作,執行後若s大於或等於零,說明售票廳的人數還未滿可進入。執行後若s小於零,則說明售票廳的人數已滿不能進入。這個實現中同時最多允許20個程序進入售票廳購票,其餘程序只能等待。
用pv原語實現程序的同步
與程序互斥不同,程序同步時的訊號量只與制約程序及被制約程序有關而不是與整組併發程序有關,所以稱該訊號量為私有訊號量。利用pv原語實現程序同步的方法是:首先判斷程序間的關係為同步的,且為各併發程序設定私有訊號量,然後為私有訊號量賦初值,最後利用pv原語和私有訊號量規定各程序的執行順序。下面我們將例1增添乙個條件,使其成為程序間是同步的。
例3
在例1的基礎之上再新增乙個功能:
(3)當乙個程序揀了乙個棋子(黑子或白子)以後,必讓另乙個程序揀乙個棋子(黑子或白子)。
分析:
第一步:確定程序間的關係。由功能(1)(2)(3)可知,程序間的關係為同步關係。第二步:確定訊號量及其值。程序a和b共享箱子這個公有資源,但規定兩個程序必須輪流去取不同色的棋子,因而相互間要互通訊息。對於程序a可設定乙個私有訊號量s1,該私有訊號量用於判斷程序a是否能去揀黑子,初值為1。對於程序b同樣設定乙個私有訊號量s2,該私有訊號量用於判斷程序b是否能去揀白子,初值為0。當然你也可以設定s1初值為0,s2初值為1。
實現:
begin
s1,s2:semaphore;
s1:=1;s2:=0;
cobegin
process a
begin
l1: p(s1);
揀黑子;
v(s2);
goto l1;
end;
process b
begin
l2:p(s2);
揀白子;
v(s1);
goto l2;
end;
coend;
end;
另外乙個問題就是p原語是不是一定在v原語的前面?回答是否定的。下面看乙個例子。
例4
設在公共汽車上,司機和售票員的活動分別是:司機:啟動車輛,正常行車,到站停車。售票員:上乘客,關車門,售票,開車門,下乘客。用pv操作對其控制。
分析:
第一步:確定程序間的關係。司機到站停車後,售票員方可工作。同樣,售票員關車門後,司機才能工作。所以司機與售票員之間是一種同步關係。
第二步:確定訊號量及其值。由於司機與售票員之間要互通訊息,司機程序設定乙個私有訊號量run,用於判斷司機能否進行工作,初值為0。售票員程序設定乙個私有訊號量stop,用於判斷是否停車,售票員是否能夠開車門,初值為0。
實現:begin stop ,run:semaphore
stop:=0;run:=0;
cobegin
driver: begin
l1: p(run);
啟動車輛;
正常行車;
到站停車;
v(stop);
goto l1;
end;
conductor:begin
l2:上乘客;
關車門;
v(run);
售票;p(stop);
開車門;
下乘客;
goto l2;
end;
coend;
end;
用pv操作還可以實現程序同步與互斥的混合問題,典型的如:多個生產者和多個消費者共享容量為n的快取區。這個例子在很多書中都有介紹,在這裡就不說了。
訊號量使用例項
include include include include include 2.6.28 module license dual bsd gpl int num 2 5 struct semaphore sem first struct semaphore sem second int thre...
linux 訊號量使用例項
define major num 254 static ssize t globalvar read struct file char size t,loff t static ssize t globalvar write struct file const char size t,loff t ...
共享記憶體 訊號量 例項
include include include include include include include define maxshm 5 定義緩衝區陣列的下標變數個數 定義3個訊號量的內部標識 int fullid int emptyid int mutexid 主函式 int main sl...