經典的進程同步問題
普通版:一類進程作為生產者,生產產品,生產的產品放入一個緩沖區,消費者從緩沖區中取出產品,需要保證生產者不可以向滿的緩沖區中添加產品,消費者不可以從空的緩沖區中取出產品。同一時刻只可以有一個生產者生產產品或者消費者消費產品。
升級版可以實現同一個時刻既有生產者生產產品,又有消費者消費產品。但是絕對不可以同一時刻多個生產者生產產品或者多個消費者消費產品。同時使用count記錄緩沖區中產品的數量。
-
生產者消費者問題
1)生產者進程和消費者進程都以異步方式運行, 但它們之間必須保持同步。
2)可利用互斥信號量$mutex$實現諸進程對緩沖池的互斥使用(不可以同時既向緩沖區中放入數據,又從緩沖區中拿出數據);利用資源信號量empty和full分別表示緩沖池中空緩沖池和滿緩沖池的數量。 假定這些生產者和消費者相互等效
/* in表示放入數據的地址,out表示取出數據的地址 buffer[n]:表示大小為n的緩沖池(由多個緩沖區組成) mutex,mutex1,mutex2:互斥型信號量,初值為1 empty,full:資源型信號量,empty表示空緩沖區的數量,full表示滿緩沖區的數量 item:表示一個數據項 */ Int in=0,out=0; Item buffer[n]; Semaphore mutex1=1,mutex2 = 1,empty=n,full=0; //生產者 Void producer(){ do{生產一個產品放入nextp;/** 進入區* 先申請資源信號量,在申請互斥信號量* mutex1控制同一個時間段內只能有一個生產者生產產品*/wait(empty);wait(mutex1);/*臨界區*/buffer[in]=nextp;in=(in+1) % n;/*退出區*/signal(mutex1);signal(full);/*對計數器count的互斥訪問*/wait(mutex);count++;signal(mutex);}while(TRUE) }//消費者 Void consumer(){ do{/*進入區*/wait(full);wait(mutex2); //消費者對緩沖區的互斥訪問/*臨界區*/nextc =buffer[out]; //只有一份out =(out+1) mod n;/*退出區*/signal(mutex2);signal(empty);/*對計數器count的互斥訪問*/wait(mutex);count--;signal(mutex);消費 nextc中的產品; }while(TRUE) }Void main(){cobeginproceducer();consumer();coend }
注意:
1)每個程序的互斥操作wait()和signal()必須成對的出現。
2)輸入進程不可以向滿的緩沖池中輸入數據,計算進程不可以從空的緩沖池中取數據
3)在每個程序中的多個wait操作順序不能顛倒,必須先執行對資源信號量的wait操作,在進行對互斥信號量的wait操作,否則可能引起進程死鎖。
4)可以使用三個互斥信號量mutex、mutex1、mutex2實現同一時刻既有生產者生產,又有消費者消費。
-
讀者—寫著問題
該問題涉計兩類進程,第一類進程是讀進程Reader,另一類進程是寫進程Writer,多個讀進程可以同時讀一個文件(共享資源),多個寫的進程不可以同時寫一個文件(對寫互斥),并且讀的時候不能寫,寫的時候不能讀(對讀互斥)。
1)問題核心:保證一個Writer進程必須與其他進程互斥地訪問共享對象的同步問題。
2)只要求讀文件的進程稱為“Reader進程”,其它進程則稱為“Writer進程”。
3)允許多個進程同時讀一個共享對象,但不允許一個Writer進程和其他Reader進程或Writer進程同時訪問共享對象(共享對象并不是臨界資源,因為他允許多個進程對其訪問)
/* 記錄型信號量解決讀者—寫者問題rmutex:讀進程對Readcount的互斥 wmutex:writer對reader和writer的互斥 readcount:表示正在讀的進程數目,只有當readcount=0的時候才需要申請wmutex權限,大于0的時候不需要 */semaphore rmutex=1, wmutex =1; int readcount =0; Void Reader(){do{wait(rmutex); //防止多個reader進程對readcount的訪問if (Readcount==0){ //如果readcount不等于0,表示有進程正在進行讀操作,絕對沒有寫操作wait(wmutex);}Readcount ++;signal(rmutex);…讀;…wait(rmutex);Readcount - -;if (Readcount==0){ //只有等于0的時候才需要釋放資源,使得寫進程可以工作signal(wmutex);}signal(rmutex);}while(TRUE); } Void writer(){do{wait(wmutex); //申請寫權限的資源寫;signal(wmutex);}while(TRUE); }Void main(){cobeginreader(); writer();Coend }
利用信號量集的機制實現讀者-寫者問題
int RN; semaphore L = RN; //表示讀者的數量 mx = 1; //對寫者進行互斥的訪問void Reader(){while(true){Swait(L, 1, 1); //申請一個讀者進程Swait(mx, 1, 0); //判斷當前是否有寫者進程在寫,該出相當于一個開關operation...Ssignal(L, 1);} }void Writer(){while(true){//此處首先申請一個mx,如果當前系統中無寫者進程,則該語句必定執行成功,Reader進程中的//Swait(mx, 1, 0)便處于關閉狀態,只需要等系統中的讀進程執行完畢,(L, RN,0)執行成//功,打開開關即可。Swait(mx, 1, 1; L, RN, 0);operation...;//釋放一個寫進程Ssignal(mx, 1);} }void main(){cobeginReader();Writer();coend; }
?
-
哲學家的進餐問題
五個哲學家共用一張圓桌,分別坐在周圍的五張椅子上,在桌子上有五只碗和五只筷子,他們的生活方式是交替地進行思考和進餐。平時,一個哲學家進行思考,饑餓時便試圖取用其左右最靠近他的筷子,只有在他拿到兩只筷子時才能進餐。進餐畢,放下筷子繼續思考。
/* 記錄型信號量解決問題 */ //每一只筷子均為臨界資源 semaphore chopstick[5]={1,1,1,1,1}; //所有的信號量均被初始化為1,第i位哲學家的活動可描述為: do{wait(chopstick[i]); //拿左手的筷子wait(chopstick[(i+1) mod 5] ); //拿右手的筷子…eat;…signal(chopstick[i]); //放左手signal(chopstick[(i +1)mod 5]); //放右手…think; }while(TRUE);
存在的問題:假如五位哲學家同時饑餓而各自拿起左邊的筷子時,就會使五個信號量chopstick均為0,當他們再試圖去拿右邊的筷子時,都將因無筷子可拿而無限等待。進入死鎖狀態。
解決辦法:
**1)**至多只允許有四位哲學家同時去拿左邊的筷子,最終能保證至少有一位哲學家能夠進餐,并在用畢后釋放出他用過的兩只筷子,從而使更多的哲學家能夠進餐。
semaphore chopstick[5]={1,1,1,1,1}; 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); //退出房間釋放信號量} }
**2)**僅當哲學家的左右兩只筷子均可用時,才允許他拿起筷子進餐。
/* 使用AND型信號量解決,本質當同時擁有兩只筷子的時候才允許拿起筷子進餐 */ semaphore chopstick[5]={1,1,1,1,1}; Philosopher i do{think;Swait(chopstick[(i+1)mod 5],chopstick[i ]); //同時分配兩只筷子eat;Ssignal(chopstick[(i+1)mod 5], chopstick[i ] ); //同時放下兩只筷子 }while(TRUE)
**3)**規定奇數號哲學家先拿他左邊的筷子,然后再去拿右邊的筷子;偶數號哲學家則相反。
semaphore chopstick[5]={1,1,1,1,1}; //第i 位哲學家的活動可描述為: do{//奇數位哲學家先拿左手的筷子if i mod 2=1 {wait(chopstick[ i ]);wait(chopstick[ ( i +1) mod 5] )}//偶數位哲學家先拿右手邊的筷子else{wait(chopstick[ ( i +1) mod 5] );wait(chopstick[ i ])}eat;signal(chopstick[ i ]);signal(chopstick[(i +1)mod 5]);…think; }while(TRUE)
?