1. 程式人生 > >第二章 程序管理(3)

第二章 程序管理(3)

經典同步問題

訊號量題目做題一般方法:
1. 分析問題,找出同步、互斥關係
2. 根據資源設定訊號量變數
3. 寫出程式碼過程,並注意P、V操作的位置
4. 檢查程式碼,模擬機器執行,體驗訊號量的變化和程式執行過程是否正確。

1.生產者-消費者問題(互斥、同步)
無論生產者、消費者使用緩衝池時應保證互斥使用(互斥訊號量mutex )
生產者和消費者間交叉有序:
 有序的控制最根源在產品數量上。
 設定兩個訊號量:
分別針對生產者、消費者設定不同的訊號量,empty和full分別表示緩衝池中空緩衝池和滿緩衝池(即產品)的數量。
empty、full兩者有天然的數量關係,在PV控制下值不斷變化,但在值等於0的點上是控制順序的關鍵。


變數和訊號量
buffer: array [ 0, …, n-1] of item;
in, out: integer :=0, 0;

不使用Counter變數,而是用訊號量

Var  mutex, empty, full: semaphore :=1, n, 0;
producer :
repeat
… 
produce an item in nexp;
… 
buffer(in):=nexp;
in:=(in+1) mod n;
until  false; 
consumer :
repeat
nextc:=buffer(out);
out:=(out+1) mod n;
consume the item in nexc;                        
until  false;   

檢查:
1. 每個程式中用於實現互斥的wait(mutex)和signal(mutex)必須成對地出現。
2. 控制順序的訊號量empty和full的wait和signal操作,成對地出現在不同的程序中。
3. 在每個程式中的多個wait操作順序不能顛倒。且應先執行對資源訊號量的wait操作,再執行對互斥訊號量的wait操作,否則可能引起程序死鎖。
4. 模擬交替執行過程,檢查控制是否正確。

模擬交叉執行
1)兩個生產者同時的情況
假設的時間片輪轉順序如下:

produce; 
produce; 
wait(e);
wait(m);
buffer(in):=nexp;
wait(e);
wait(m);
buffer(in):=nexp;
in:=(in+1)mod n;
signal(m);
signal(f);
in:=(in+1)mod n;
signal(m);
signal(f);

1號生產者的wait操作使e=n-1,m=0
當1號正在in=0的buffer[0]放入產品時,2號來到,wait(e)仍通過,e=n-2;但wait(m)會使2號阻塞。m=-1,e=n-2。
轉入1號生產者執行使in=1,,喚醒m上的等待者——2號生產者,但可能並不立即切換到2號執行,而是其分到的cpu時間完成後再轉到2號。此時m=0,f=1。
回到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;

設當前執行到一個臨界點,緩衝區滿了,而生產者先來了要生產。
e=0;m=1;f=n
注意:signal原語喚醒的因wait阻塞的程序後該程序並不需再重新執行wait

##AND訊號量的方式

consumer :
    repeat
    nextc:=buffer(out);
    out:=(out+1) mod n;
    consume the item in nexc;
until  false;

2. 哲學家進餐問題(互斥、死鎖)
五個哲學家共用一張圓桌,分別坐在周圍的五張椅子上,在桌子上有五隻碗和五隻筷子,他們的生活方式是交替地進行思考和進餐。平時,一個哲學家進行思考,飢餓時便試圖取用其左右最靠近他的筷子,只有在他拿到兩隻筷子時才能進餐。進餐畢,放下筷子繼續思考。
可見:相鄰兩位不能同時進餐;最多隻能有兩人同時進餐。
1)記錄型訊號量解決哲學家進餐問題
筷子是臨界資源,在一段時間內只允許一個哲學家使用。為實現對筷子的互斥使用,用一個訊號量表示一隻筷子,五個訊號量構成訊號量陣列。
Var chopstick: array [0, …, 4] of semaphore;
所有訊號量均被初始化為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) 就餐死鎖問題
假如五位哲學家同時飢餓而各自拿起左邊的筷子時,就會使五個訊號量chopstick均為0,當他們再試圖去拿右邊的筷子時,都將因無筷子可拿而無限等待。
解決方法:
->數量控制:
至多隻允許有四位哲學家同時去拿左邊的筷子,最終能保證至少有一位哲學家能夠進餐,並在用畢後釋放出他用過的兩隻筷子,從而使更多的哲學家能夠進餐。
—限制併發執行的程序數

->一刀切:
僅當哲學家的左右兩隻筷子均可用時,才允許他拿起筷子進餐。
—採用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. 讀者-寫者問題(有條件的互斥)
一個數據檔案被多個程序共享。Reader程序只要求讀檔案,Writer程序要求寫入內容。
合理的同步關係是:
->多個讀程序可同時讀;
->Writer程序與任何其他程序(包括Reader程序或其他Writer程序)不允許同時訪問檔案。

讀者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

利用訊號量集機制解決讀者——寫者問題
• 引入訊號量L控制讀者的數目,初值為RN。
• 互斥訊號量mx,初值為1。
• 利用訊號量集的一種特殊情況——開關。
讀者:判斷L,判斷是否有寫者;
寫者:判斷是否有讀者;

reader : 
repeat
   Swait(L, 1, 1);
   … 
  // 讀操作;
   … 
   Ssignal(L, 1);
until  false;

writer : 
repeat
   Swait(mx, 1, 1; L, RN, 0);
   //寫操作;
   Ssignal(mx, 1);
until  false;