1. 程式人生 > >第二章 程序的描述與控制(2)

第二章 程序的描述與控制(2)


2.4經典同步問題


一、生產者——消費者問題(互斥、同步)
生產者與生產者,消費者與消費者之間是互斥的關係。生產者與消費者之間是順序關係。
設定訊號量empty,full以及互斥訊號量mutex設初值為1。
(1)兩個生產者同時的情況:
producer :
int in=0,out=0;
item buffer[n];
semaphore mutex=1,empty=n,full=0;
void producer(){
do{

produce an item in nexp;

wait(empty);//先執行對資源的訊號量的操作然後進行對互斥訊號量的操作。操作順序不可顛倒防止程序死鎖。
wait(mutex);
buffer(in):=nexp;
in:=(in+1) mod n;
signal(mutex);//訊號量成對的出現
signal(full);
}while(true);
}
過程分析:
1)1號生產者的wait操作使e=n-1,m=0
2)當1號正在in=0的buffer[0]放入產品時,2號來到,wait(e)仍通過,e=n-2;但wait(m)會使2號阻塞。m=-1,e=n-2。
3)轉入1號生產者執行使in=1,,喚醒m上的等待者——2號生產者,但可能並不立即切換到2號執行,而是其分到的cpu時間完成後再轉到2號。此時m=0,f=1。
4)回到2號程序後,將產品放入緩衝區;in=2;m=1;f=2。
(2)生產者等待消費者的情況


produce;
wait(e);
wait(m);
buffer(in):=nexp;
wait(f);
wait(m);
nextc:=buffer(out);
in:=(in+1)mod n;
signal(m);
signal(f);
out:=(out+1) mod n;
signal(m);
signal(e);
consume;
過程分析:
1)設當前執行到一個臨界點,緩衝區滿了,而生產者先來了要生產。
2)e=0;m=1;f=n當第一個生產者來了,e=-1被阻塞,只有等到一個消費者來時程式才可以繼續。此時wait(f),f=n-1,wait(m),m=0,繼續向下執行,執行過後signal,m=1,f=n。
3)out:=(out+1) mod n,取出產品,當signal(m),m=2;signal(e),e=0.
注意:signal原語喚醒的因wait阻塞的程序後該程序並不需再重新執行wait。

(3)2個生產者2個消費者在這裡插入圖片描述
AND訊號量的方式
consumer :
repeat
Swait(full,mutex);
nextc:=buffer(out);
out:=(out+1) mod n;
Ssignal(mutex,empty);
consume the item in nexc;
until false;
二、哲學家就餐問題(互斥)
筷子是臨界資源,要實現對筷子的互斥相鄰兩位不能同時進餐;最多隻能有兩人同時進餐。
解決方案:
(1)至多隻允許有四位哲學家同時去拿左邊的筷子,最終能保證至少有一位哲學家能夠進餐,並在用畢後釋放出他用過的兩隻筷子,從而使更多的哲學家能夠進餐。
第i 位哲學家的活動可描述為:
repeat
wait(chopstick[ i ]);
wait(chopstick[ ( i +1) mod 5] );

eat;

signal(chopstick[ i ]);
signal(chopstick[ ( i +1) mod 5] );

think;
until false;
(2)僅當哲學家的左右兩隻筷子均可用時,才允許他拿起筷子進餐。—採用AND訊號量

Var chopstick: array [0, …, 4] of semaphore:=(1, 1, 1, 1, 1);
Process i
repeat
think;
Swait(chopstick[ ( i +1) mod 5] , chopstick[ i ] );
eat;
Ssignal(chopstick[ ( i +1) mod 5] , chopstick[ i ] );
until false;
(3) 規定奇數號哲學家先拿他左邊的筷子,然後再去拿右邊的筷子;偶數號哲學家則相反。保證總會有一個哲學家能同時獲得兩隻筷子而進餐。—採用IF程式設計控制
三、讀者——寫者問題(有條件的互斥)
Writer程序與任何其他程序(包括Reader程序或其他Writer程序)不允許同時訪問檔案。
(1)寫者操作要和其他的都互斥,所以必要判斷互斥訊號量, 沒有變化:
(2)只有第一個讀程序進行互斥判斷;
(3)只要有一個“讀程序”在讀就不釋放,“寫程序”就不能寫。(一種讀者優先的方式

寫者Writer :
repeat
wait(wmutex);
寫入檔案;
signal(wmutex);
until false;
讀者Reader :
begin
repeat
wait(rmutex);
if Readcount=0 then wait(wmutex);//防止寫程序再進入,不影響其他讀程序
Readcount :=Readcount +1;
signal(rmutex);

perform read operation;

wait(rmutex);
Readcount :=Readcount -1;
if Readcount=0 then signal(wmutex);
signal(rmutex);
until false;
end
寫者優先的方式
在這裡插入圖片描述讀者間起作用:
Readcount變數,rmutex訊號量
寫者間起作用:
writecount變數,mutex訊號量
讀者與寫者間起作用:
wmutex
S
四、黑白棋子問題
兩種情況的解決辦法:
(1)執黑子一方先下
訊號量:b=1,w=0;
黑:
while(沒結束){
wait(b);
下一黑棋;
signal(w);
}
白:
while(沒結束){
wait(w);
下一白棋;
signal(b);
}
另一種方式:
semaphore bfg=1;wfg=0;
void main(){
black();white();
void black(){
while(true){
wait(bfg);
if whereput(){
put a black chess;
}
else break;
signal(wfg);
}
}
void white(){
while(true){
wait(wfg);
if whereput(){
put a white chess;
}else break;
signal(bfg);
}
}
}
(2)雙方都可以先下,誰先搶到棋盤誰先下。然後開始輪流下子。
利用互斥訊號量與特殊標誌變數的結合使用實現有序控制
semaphore bfg=1;wfg=0;m=1;
boolean fg=F;
void main(){
black();
white();
}
void black(){
wait(m);
if !fg{
bfg=1;wfg=0;fg=T;
signal(m);
while(true){
wait(bfg);
if whereput(){
put a black chess;
signal(wfg);
}
else{
signal(wfg);
break;
}}}
void white(){
wait(m);
if !fg{
bfg=0;wfg=1;fg=T;
}
signal(m);
while(true){
wait(wfg);
put a white chess;
signal(bfg);
}}
五、嗜睡的理髮師問題

Int cout=0;        
Semaphore mutex=1,sofa=N,empty=1,full=0,cut=0,payment=0,receipt=0;       process guesti() 顧客i              
 {   wait(mutex);  //count既用於判斷,也要修改,所以為臨界資源,用mutex管理互斥,但由於是分支結構,所以要在每個分支結構中注意離開count的臨界區時使用signal釋放臨界資源            
 if(count>N)// 沙發中已經坐滿客人N個和正在理髮的1位,沒有沙發,客人離開理髮店  {signal(mutex); exit shop; }             
 else                 
 { count=count+1;                  
  if(count>1)  //count>1,意味著原來理髮店裡有客人,所以不能坐理髮椅,需要坐到沙發上等待                    
  { signal(mutex); 
  wait(sofa);       //申請沙發,肯定能得到                      
  sit on sofa;                      
  wait(empty);      //申請理髮椅,等不到阻塞,得到,則從沙發上站起,準備坐到理髮椅上                      
  get up form sofa;                     
   signal(sofa);       //歸還沙發 
    }                 
     else                    
      { signal(mutex);   
      wait(empty);     //count==1,意味著這個店裡只有這一個顧客,他不必要申請沙 發,直接申請理髮椅即可 
       }                   
        sit on the baber_chair;                    
        signal(full);    //若理髮師阻塞,則喚醒理髮師,若未阻塞,則將full由0增1,理髮師申請理髮時即可通過                    
         wait(cut);      //測試理髮是否完成,沒有則阻塞                   
         pay;                        
         signal(payment);  //若理髮師阻塞,則喚醒理髮師告知其已經付費,若未阻塞,則將paymentl由0增1,理髮師申請理要求付費時即可通過                   wait(receipt);     // //測試理髮師收費是否完成,沒有則阻塞                    
   get up form the baber_chair;  //理髮師收費完成,顧客離開理髮椅                  signal(empty);    //釋放理髮椅                      wait(mutex);      //對count 臨界資源操作,用mutex完成互斥                   count=count-1;                   
   signal(mutex);                   
   exit shop;  }              
   }          
    process barber( )           
     { while(1)               
      {wait(full);    //測試理髮椅上是否有顧客,無則阻塞                
      cut hair;                 
      signal(cut);    //告知顧客理髮完成               
       wait(payment);  //測試顧客是否付費                
       accept pament;                 
       signal(receipt);  //告知顧客收費完
                      }             
                      }         
                       main( )         
                        {cobegin              
                         { guesti();               
                          Barber();              
                          }          
                           }