有一個倉庫,可以存放 A 和 B 兩種産品,倉庫的存儲空間足夠大,但要求: (1)一次隻能存入一種産品(A 或 B); (2)-N < (A 産品數量-B 産品數量) < M。 其中,N 和 M 是正整數。試用“存放 A”和“存放 B”以及 P、V 操作描述産品 A 與 産品 B 的入庫過程。
Semaphore Sa = M - 1;
Semaphore Sb = N - 1;
//代表還能存入的數量
Semaphore mutex = 1;
process_A() {
while(1){
P(Sa); //取一個A産品準備入庫
P(mutex);
A産品入庫;
// A産品入庫後還能存入A産品數量-1
V(mutex);
V(Sb); //還能存入B産品數量+1
}
}
process_B() {
while(1){
P(Sb); //取一個B産品準備入庫
P(mutex);
B産品入庫;
// B産品入庫後還能存入B産品數量-1
V(mutex);
V(Sa); //還能存入A産品數量+1
}
}
桌子上有一隻盤子,最多可容納兩個水果,每次隻能放入或取出一個水果。爸爸專向盤子放蘋果( apple),媽媽專向盤子中放桔子( orange);兩個兒子專等吃盤子中的桔子,兩個女兒專等吃盤子中的蘋果。請用 P、 V 操作來實作爸爸、媽媽、兒子、女兒之間的同步與互斥關系。
Semaphore mutex = 1; //互斥信号量, 其初值為1
Semaphore empty = 2; //記錄允許向盤子中放入水果的個數,初值為2
Semaphore orange = 0; //盤子中已放入的蘋果的個數,初值為0
Semaphore apple = 0; //盤子中已放入的桔子的個數,初值為0
main()
{
Cobegin
{
father //父親程序
{
while (true)
{
P(empty); //減少盤中可放入的水果數
P(mutex); //申請向盤中取、放水果
向盤中放蘋果;
V(mutex); //允許向盤中取、放水果
V(apple); //遞增盤中的蘋果數
}
}
mother //母親程序
{
while (true)
{
P(empty); //減少盤中可放入的水果數
P(mutex); //申請向盤中取、放水果
向盤中放桔子;
V(mutex); //允許向盤中取、放水果
V(orange); //遞增盤中的桔子數
}
}
daughteri(i=1,2) //兩女兒程序
{
while (true)
{
P(apple); //減少盤中蘋果數
P(mutex); //申請向盤中取、放水果
取盤中蘋果;
V(mutex); //允許向盤中取、放水果
V(empty); //遞增盤中可放入的水果數
}
}
sonj(j=1,2) //兩兒子程序
{
while (true)
{
P(orange); //減少盤中桔子數
P(mutex); //申請向盤中取、放水果
取盤中桔子;
V(mutex); //允許向盤中取、放水果
V(empty); //遞增盤中可放入的水果數
}
}
}
Coend
}
有一個理發師,一把理發椅和 N 把供等候理發的顧客坐的椅子。如果沒有顧客,則理發師便在理發師椅子上睡覺;當一個顧客到來時,必須喚醒理發師進行理發;如果理發師正在理發時又有顧客來到,則如果有空椅子可坐,他就坐下來等,如果沒有空椅子,他就離開。為理發師和顧客各編一段程式(僞代碼)描述他們的行為,要求不能帶有競争條件。
Semaphore mutex = 1; //互斥信号量,初值為1.
Semaphore Wait = 0; //等待服務的顧客數
Semaphore barbers= 0; //等待顧客的理發師數
Int custNum = 0; //等待的顧客(還沒理發的)
Costumer()
{
while(true)
{
P(mutex); //申請理發
if(custNum>0)
{
if(custNum<N) //若等待人數小于N
{
V(mutex); //釋放程序等待
CustNum++; //增加等待人數
}
else //若等待人數超過N
{
V(mutex); //釋放程序等待
離開;
}
}
else //若目前無人等待
{
V(mutex); //釋放程序等待
V(barbers); //如果必要的話,喚醒理發師
理發;
離開;
P(mutex); //要求程序等待
custNum--; //顧客人數減1
V(mutex); //釋放程序等待
V(wait); //等待人數減1
}
}
}
Barber()
{
while(true)
{
P(mutex); //要求程序等待
if(custNum ==0) //目前無顧客
{
V(mutex); //釋放程序等待
P(barbers); //理發師睡覺
}
else
{
V(mutex); //釋放程序等待
理發;
}
}
}
吸煙者問題。三個吸煙者在一間房間内,還有一個香煙供應者。為了制造并抽掉香煙,每個吸煙者需要三樣東西:煙草、紙和火柴。供應者有豐富的貨物提供。三個吸煙者中,第一個有自己的煙草,第二個有自己的紙,第三個有自己的火柴。供應者将兩樣東西放在桌子上,允許一個吸煙者進行對健康不利的吸煙。當吸煙者完成吸煙後喚醒供應者,供應者再放兩樣東西(随機地)在桌面上,然後喚醒另一個吸煙者。試為吸煙者和供應者編寫程式解決問題。
Semaphore S = 1; //供應者
Semaphore S1,S2,S3; //三個吸煙者
S1 = S2 = S3 = 0;
bool flag1,flag2,fiag3; //三種吸煙原料
fiag1=flag2=flag3=true;
Apply() //供應者
{
While(true)
{
P(S);
取兩樣香煙原料放桌上,由flagi标記;
if (flag2 && flag3) //供紙和火柴
{
V(S1); //喚醒吸煙者一
}
else if(flag1 && fiag3) //供煙草和火柴
{
V(S2); //喚醒吸煙者二
}
else //供煙草和紙
{
V(S3); //喚醒吸煙者三
}
}
}
Smoker1() //吸煙者一
{
While(true)
{
P(S1);
取原料;
做香煙;
V(S); //喚醒供應者
吸香煙;
}
}
smoker2() //吸煙者二
{
While(true)
{
P(S2);
取原料;
做香煙;
V(S); //喚醒供應者
吸香煙;
}
}
Smoker3() //吸煙者三
{
While(true)
{
P(S3);
取原料;
做香煙;
V(S); //喚醒供應者
吸香煙;
}
}
面包師問題。面包師有很多面包和蛋糕,由 n 個銷售人員銷售。每個顧客進店後先取一個号,并且等着叫号。當一個銷售人員空閑下來,就叫下一個号。請分别編寫銷售人員和顧客程序的程式。
Semaphore buyer= 0; //顧客人數
Semaphore seller = n; //銷售人員數
Semaphore mutex_s = 1; //用于銷售人員的互斥信号量
Semaphore mutex_b = 1; //用于顧客的互斥信号量
int count_s = 0; //記錄取号的值
int count_b = 0; //記錄叫号的值
void Buy() //顧客程序
{
進店;
P(mutex_b); //取号
count_b++;
V(mutex_b);
V(buyer);
P(seller); //等待叫号
買面包;
離開
}
void Sell()
{
while(true)
{
P(buyer);
P(mutex_s); //叫号
count_s++;
叫編号為count_s的顧客;
V(mutex_s);
V(seller);
}
}
桌上有一空盤,運作存放一隻水果,爸爸可向盤中放蘋果,也可放桔子,兒子專等吃盤中的桔子,女兒專等吃盤中的蘋果。規定當盤中空時一次隻能放一個水果供吃者取用,用 P,V 原語實作爸爸兒子和女兒 3 個并發程序的同步。
Semaphore S = 1; //S 表示盤子是否為空;
Semaphore Sa = 0; //Sa 表示盤中是否有蘋果;
Semaphore Sb = 0; //Sb 表示盤中是否有桔子;
Father() //父親程序
{
while(TRUE)
{
P(S);
将水果放入盤中;
if (放入的是桔子)
V(Sb);
else
V(Sa);
}
}
Son() //兒子程序
{
while(TRUE)
{
P(Sb);
從盤中取出桔子;
V(S);
吃桔子;
}
}
Daughter() //女兒程序
{
while(TRUE)
{
P(Sa);
從盤中取出蘋果;
V(S);
吃蘋果;
}
}
寫者優先的讀者--寫者問題。讀者-寫者問題為資料庫通路建立了一個模型。例如,一個系統,其中有許多競争的程序試圖讀寫其中的資料,多個程序同時讀是可以接受的,但如果一個程序正在更新資料庫,則所有的其他程序都不能通路資料庫,即使讀操作也不行。寫者優先是指當一個寫者到達時,将阻止其後面的讀者進入資料庫,直到其離開為止。
Semaphore Mut1, Mut2, Wmutex, Fmutex; //互斥信号量
int Rcount, Wcount; //讀寫者人數
Mut1 = Mut2 = WMutex = Fmutex = 1;
Rcount = Wcount = 0;
Writer() //寫者程序
{
While(true)
{
P(Mut1);
Wcount=Wcount+1;
If (Wcount==1)
{
P(Fmutex); //如有讀者,寫者阻塞在此處
}
V(Mut1);
P(WMutex);
寫;
V(Wmutex);
P(Mut1);
Wcount=Wcount-1;
If (Wcount==0)
{
V(Fmutex);
}
V(Mut1);
}
}
Reader() //讀者程序
{
While(true)
{
P(Mut2);
Rcount=Rcount+1;
If (Rcount==1)
{
P(Fmutex);
}
V(Mut2);
讀;
P(Mut2);
Rcount=Rcount-1;
If (Rcount==0)
{
V(Fmutex);
}
V(Mut2);
}
}
在天津大學與南開大學之間有一條彎曲的小路,這條路上每次每個方向上隻允許一輛自行車通過。但其中有一個小的安全島 M,同時允許兩輛自行車停留,可供兩輛自行車已從兩端進入小路的情況下錯車使用。如圖所示。
下面的算法可以使來往的自行車均可順利通過。其中使用了 4 個信号量, T 代表天大路口資源, S 代表南開路口資源, L 代表從天大到安全島一段路的資源, K 代表從南開到安全島一段路的資源。程式如下,請在空白位置處填寫适當的 PV 操作語句,每處空白可能包含若幹個 PV 操作語句。
begin
t:=1;s:=1;l:=1;k:=1;
cobegin
從天大到南開的程序
begin
______(1)______
通過 L 路段;
進入安全島 M;
______(2)______
通過 K 路段
______(3)______
end
從南開到天大的程序
begin
略,與“從天大到南開的程序”相反。
end
coend
end
解答:
(1) P(t); P(l);
P1()
{
While(true)
{
X = produce(); //生成一個數
P(empty); //是否有空單元格
P(mutex); //進入臨界區
Put();
if(X%2 == 0)
V(s2); //如果是偶數,向P3發出信号
else
V(s1); //如果是奇數,向P2發出信号
V(mutex); //離開臨界區,釋放互斥信号量
}
}
P2()
{
While(true)
{
P(s1); //收到P1發送來的信号,已産生奇數
P(mutex); //進入臨界區
getodd();
countodd():=countodd()+1;
V(mutex);
V(empty); //離開臨界區,釋放互斥信号量
}
}
P3()
{
While(true)
{
P(s2) //收到P1發送來的信号,已産生偶數
P(mutex); //進入臨界區
geteven();
counteven():=counteven()+1;
V(mutex);
V(empty); //離開臨界區,釋放互斥信号量
}
}