用P、V操作解決進程同步問題的解題步驟

藍顏色是格外注意的

在這裏插入圖片描述

在這裏插入圖片描述
還有讀讀共享,讀寫互斥問題。
要背會四個模式,套用模式




在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

例題講解
1)生產者-消費者問題
一般意義的“生產者—消費者”問題:N個buffer,多個生產者,多個消費者,循環存取buffer。這就是一般意義的“生產者—消費者”問題。利用記錄型信號量解決一般意義的“生產者—消費者”問題算法描述,請看教材。
說明:
(1)由於buffer有N個,而且buffer又是臨界資源,因此,需要增加一個信號量mutex來實現對buffer的互斥訪問,其初始值爲1。需要特別強調的是,這種情況下,mutex不能省略。
(2)這種情況下,只要保證爲不同的進程分配不同buffer,putdata和getdata操作是可以同時進行的,因此,對buffer的互斥訪問不是發生在對buffer的存取操作上,而是發生在對buffer的分配上。
2)“哲學家進餐”問題
教材中解決哲學家進餐問題的算法有可能發生死鎖,爲避免死鎖,可以採用以下三種策略:
策略一原理:至多隻允許四個哲學家同時進餐,以保證至少有一個哲學家能夠進餐,最終總會釋放出他所使用過的兩支筷子,從而可使更多的哲學家進餐。定義信號量count,只允許4個哲學家同時進餐,這樣就能保證至少有一個哲學家可以就餐。
semaphore chopstick[5]={11111};
semaphore count=4;
void philosopher(int i)
{while(true)
{
think();
wait(count); //請求進入房間進餐
wait(chopstick[i]); //請求左手邊的筷子
wait(chopstick[(i+1)%5]); //請求右手邊的筷子
eat();
signal(chopstick[(i+1)%5]); //釋放右手邊的筷子
signal(chopstick[i]); //釋放左手邊的筷子
signal(count); //退出房間釋放信號量
}
}

策略二原理:僅當哲學家的左右兩支筷子都可用時,才允許他拿起筷子進餐。可以利用AND 型信號量機制實現,也可以利用信號量的保護機制實現。利用信號量的保護機制實現的思想是通過記錄型信號量mutex對取左側和右側筷子的操作進行保護,使之成爲一個原子操作,這樣可以防止死鎖的出現。描述如下:
semaphore mutex = 1 ;
semaphore chopstick[5]={11111};
void philosopher(int i)
{while(true)
{
think();
wait(mutex);
wait(chopstick[(i+1)%5]);
wait(chopstick[i]);
signal(mutex);
eat();
signal(chopstick[(i+1)%5]);
signal(chopstick[i]);
}
}
策略三原理:規定奇數號的哲學家先拿起他左邊的筷子,然後再去拿他右邊的筷子;而偶數號的哲學家則相反。按此規定,將是12號哲學家競爭1號筷子,34號哲學家競爭3號筷子。即五個哲學家都競爭奇數號筷子,獲得後,再去競爭偶數號筷子,最後總會有一個哲學家能獲得兩支筷子而進餐。
semaphore chopstick[5]={11111};
void philosopher(int i)
{while(true)
{
think();
if(i%2 == 0) //偶數哲學家,先右後左。
{
wait (chopstick[(i + 1)%5]) ;
wait (chopstick[i]) ;
eat();
signal (chopstick[(i + 1)%5]) ;
signal (chopstick[i]) ;
}
else //奇數哲學家,先左後右。
{
wait (chopstick[i]) ;
wait (chopstick[(i + 1)%5]) ;
eat();
signal (chopstick[i]) ;
signal (chopstick[(i + 1)%5]) ;
}
}

3)“讀者—寫者”問題的演變
從本質上講,讀者—寫者問題要解決:讀、讀共享;寫、寫互斥;寫、讀互斥。有兩種解決模式:
模式一,讀者優先的“讀者—寫者”問題解決模式(算法描述請參考教材):
①定義互斥信號量wmutex,實現寫、寫互斥和寫、讀互斥。
②定義整型變量Readcount表示正在讀的進程數目。由於只要有一個Reader進程在讀,便不允許Writer進程寫,因此僅當Readcount=0,即無Reader進程在讀時,Reader才需要執行Wait(wmutex)操作。若Wait(wmutex)操作成功,Reader進程便可去讀,相應地,做Readcount+1操作。同理,僅當Reader進程在執行了Readcount減1操作後其值爲0時,才需執行signal(wmutex)操作,以便讓Write進程寫。
③由於Readcount爲多個讀進程共享(修改),因此需要以互斥方式訪問,爲此,需要定義互斥信號量rmutex,保證讀進程間互斥訪問Readcount。
說明:在讀者—寫者問題中,實現“讀、讀共享”是有一定難度的,請掌握該模式(由②和③構成)。
模式二,寫者優先的“讀者—寫者”問題解決模式,算法描述如下:
設3個信號量:
rmutex --- 讀互斥信號量,初值爲1;
wmutex --- 寫互斥信號量,初值爲1;
s --- 用於在寫進程到達後封鎖後續的讀者,初值爲1;
count --- 共享變量,用於記錄當前正在讀文件的讀者數目,初值爲0;
semaphore rmutex=1, wmutex=1, s=1;
int count=0;
main() 
{
	Cobegin
	Reader();
	Writer();
	Coend
}
	Reader() 
	{
	While(1)  {
	P(s);  
	P(rmutex);
	If (count==0) P(wmutex);  /*當第1個讀者讀文件時,阻止寫者寫*/
	count++
	V(rmutex);
	V(s);
	讀文件;
	P(rmutex);
	count--;
	If (count==0) V(wmutex);  /*當最後1個讀者讀完文件時,允許寫者寫*/
	V(rmutex);
	}
	}
	Writer()
	 {
	While(1)  {
	P(s);
	P(wmutex);
	寫文件;
	V(wmutex);
	V(s);
	}
}


例題解析
【例1】 桌上有1空盤,允許存放1個水果。爸爸向盤中放蘋果,也可以向盤中放桔子。兒子專等喫盤中的桔子,女兒專等喫盤中的蘋果。規定當盤空時一次只能放1個水果供喫者取用。請用Wait()Signal()原語實現爸爸、兒子、女兒三個併發進程的同步。
【南京大學2000】
【分析】這是複雜情況的“生產者—消費者”問題,既有同步又有互斥。爸爸進程與兒子進程、女兒進程需要同步,兒子進程與女兒進程需要互斥。設置4個信號量S(盤子是否爲空,初值爲1)、So(盤中是否有桔子,初值爲0)、Sa(盤中是否有蘋果,初值爲0)和mutex(用於對盤子的互斥訪問,初值爲1)。由於只有一個盤子(相當於只有一個buffer),對盤子的互斥訪問發生在對盤子的存取操作上,S、So和Sa就可以保證對盤子的互斥操作了,故mutex也可以省略。
解:設三個信號量:
S --- 盤子是否爲空,初值爲1;
So --- 盤中是否有桔子,初值爲0;
Sa --- 盤中是否有蘋果,初值爲0;

Semaphore S=1, So=0, Sa=0;
Main() {
Cobegin
Father();
Son();
Daughter();
Coend
}
Father() {
While(1)  {
Wait(S);   將水果放入盤中;
If  (放入的是桔子)  Signal(So);
Else   Signal(Sa);
}
}
Son() {
While(1)  {
Wait(So);   從盤中取出桔子;Signal(S); 喫桔子;
}
}
Daughter() {
While(1)  {
Wait(Sa);   從盤中取出蘋果;Signal(S); 喫蘋果;
}
}



【例2】 如圖1所示,有多個PUT操作同時向Buff1放數據,有一個MOVE操作不斷地將Buff1的數據移到Buff2,有多個GET操作不斷地從Buff2中將數據取走。Buff1的容量爲m,Buff2的容量是n,PUT、MOVE、GET每次操作一個數據,在操作的過程中要保證數據不丟失。試用P、V原語協調PUT、MOVE的操作,並說明每個信號量的含義和初值。
 
圖1  進程操作圖
【分析】這裏存在兩個一般意義的“生產者—消費者”問題,PUT(生產者)與MOVE(消費者)之間,需要設置三個信號量;MOVE(生產者)與GET(消費者)之間,需要設置三個信號量。PUT進程套用生產者進程即可,MOVE進程只有在Buff1有新數據且Buff2有空閒區的時候才移動數據,GET進程套用消費者進程即可。
答案:設置6個信號量full1、empty1、B-M1、full2、empty2、B-M2,它們的含義和初值如下:
1)	full1表示Buff1是否有數據,初值爲02)	empty1表示Buff1有空間,初值爲m;
3)	B-M1表示Buff1是否可操作,初值爲14)	Full2表示Buff2是否有數據,初值爲05)	Empty2表示Buff2有空間,初值爲n;
6)	B-M2表示Buff2是否可操作,初值爲1<PUT類進程>
 {
	repeat
	P(empty1)/*判斷Buff1是否有空間,沒有則等待 */     
	P(B-M1)/*是否可操作Buff1*/
	PUT;                 
	V(B-M1)/*設置Buff1可操作標誌 */               
	V(full1)/*設置Buff1有數據的標誌 */ 
	until false 
}
<MOVE類進程>
 {
	repeat
	P(full1)/*判斷Buff1是否有數據,沒有則等待*/
	P(empty2)/*判斷Buff2是否有空間,沒有則等待*/      
	P(B-M1)/*是否可操作Buff1  */
	P(B-M2)/*是否可操作Buff2  */
	MOVE;                 
	V(B-M1)/*設置Buff1可操作標誌*/  
	V(B-M2)/*設置Buff2可操作標誌*/  
	V(empty1)/*設置Buff1有空間標誌*/             
	V(full2)/*設置Buff2有數據標誌*/ 
	until false 
}

<GET類進程>
           {
repeat
P(full2)/*判斷Buff2是否有數據,沒有則等待 */     
P(B-M2)/*是否可操作Buff2*/
GET;                 
V(B-M2)/*設置Buff2可操作標誌 */               
V(empty2)/*設置Buff2有空間的標誌 */ 
until false
 
【例3】(8分)某銀行提供1個服務窗口和10個供顧客等待的座位。顧客到達銀行時,若有空座位,則到取號機上領取一個號,等待叫號。取號機每次僅允許一位顧客使用,當營業員空閒時,通過叫號選取1位顧客,併爲其服務。顧客和營業員的活動過程描述如下:
cobegin
{
   process 顧客i
   {
      從取號機獲得一個號碼;
      等待叫號;
      獲得服務;
   }

   process 營業員
   {
      while (TRUE)
         {
            叫號;
            爲顧客服務;
         }
   }
} coend

請添加必要的信號量和P、V(或wait()signal())操作,實現上述過程中的護持與同步。要求寫出完整的過程,說明信號量的含義並賦初值。               【全國統考 2011】

解:
semaphore  emptySeats:=10       //空閒座位數
semaphore  fullSeats:=0          //已佔座位數
semaphore  mutex:=1            //顧客使用取號機互斥信號量

cobegin
{
   process 顧客i
   {
      wait(emptySeats);        //獲取一個座位
      wait(mutex);             //佔用取號機取號
從取號機獲得一個號碼;
signal(mutex)            //釋放取號機
      signal(fullSeats)         //座位上增加一個顧客
等待叫號;
signal(emptySeats);      //釋放一個座位
      獲得服務;
      
   }

   process 營業員
   {
      while (TRUE)
         {
            wait(fullSeats);        //座位上減少一個顧客
            叫號;
            爲顧客服務;
         }
   }
} coend
講評:此題爲生產者-消費者問題的翻版。課本上的哲學家進餐問題、生產者–消費者問題、讀者–寫者問題爲基礎性的進程同步問題,需要認真真正掌握,以此爲基礎用於解決其他進程同步問題。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章