經典的進程同步問題

生產者消費者問題

問題

一組生產者向一組消費者提供產品,它們共享一個有界緩衝區,生產者向其中投放產品,消費者從中取得產品。

規則

對於生產者:生產者生產一個產品(數據),正常放入倉庫(緩衝區)。若有人正在訪問倉庫(緩衝區),則需要等待;若無則訪問。若倉庫(緩衝區)已滿,則等待,等待一個消費者消費一個產品(數據),讓倉庫(緩衝區)不滿,再喚醒;若不滿則可直接放入。
在這裏插入圖片描述
對於消費者:消費者消費一個產品(數據),要去倉庫(緩衝區)去取。若有人正在訪問倉庫(緩衝區),則等待。若倉庫(緩衝區)爲空,則等待一個生產者來生產產品(數據)供消費者消費;若不爲空則取一個產品(數據)進行消費。
在這裏插入圖片描述
緩衝區是個臨界資源,諸進程對緩衝區的操作程序是一個共享臨界區,所以,還有個互斥的問題。

設置兩個同步信號量及一互斥信號量
Empty:說明空緩衝單元的數目,其初值爲有界緩衝區的大小n。即倉庫有多少空位。
Full: 說明滿緩衝單元的數目(即產品數目),其初值爲0。即倉庫已經有多少產品(有多少個位置被佔)
Mutex: 說明該有界緩衝區是一臨界資源,必須互斥使用,其初值爲1,保證任何時候只有一個進程使用緩衝區

Int in=0;out=0;
Item buffer[n];
Semaphore mutex=1,empty=n,full=0;
//生產者
void   procedure() {
               do{
      					produce an item in nextp;wait(empty);//檢驗是否滿了,若empty<0則阻塞 不執行下面的代碼
                            wait(mutex);//表示正在使用緩衝區
                            buffer(in)=nextp;
                            in=(in+1)%n;
                            signal(mutex);//釋放緩衝區
                            signal(full);//將產品數+1 做到進程同步
   }while(TRUE);
}

//消費者
Void consumer(){
               do{ 
                         wait(full);//檢查是否爲空,若full<0則說明緩衝區沒有產品消費了 阻塞進程
                          wait(mutex);//表示正在使用緩衝區
                          nextc=buffer(out);
                          out=(out+1)%n;
                           signal(mutex);//釋放緩衝區
                           signal(empty);//空位+1 做到進程同步
            				consumer the item in nextc;}while (TRUE);
}

Void main() {
	cobegin 
	     procedure();
	     consumer();
	coend;
}

注:
兩個wait不可以互換位置,因爲若互換,假設生產者進程執行,佔用了臨界資源mutex,而此時發現臨界區滿了(empty<0),便將自己阻塞而並未釋放mutex;此時消費者資源過來,發現臨界資源mutex(臨界區)正在被人使用,便也阻塞,從而造成死鎖。
兩個signal同樣不可以互換位置,同理。

哲學家進餐問題

問題

五個哲學家共用一張圓桌,分別坐在周圍的五張椅子上,在圓桌上有五碗通心粉和五根筷子,他們的生活方式是交替地進行思考和進餐。平時,哲學家進行思考,飢餓時便試圖取用其左右兩邊最靠近他的筷子,只有在他拿到兩根筷子時才能進餐。進餐後,放下筷子繼續思考。
在這裏插入圖片描述

分析

兩位哲學家不能擡起一根筷子喫飯,所以筷子是臨界資源,一次只能在一個人的手裏。
解決方法:用一個記錄型信號量來控制一根筷子的互斥使用,由這5個信號量構成信號量數組。其描述如下:

var chopstick: array [0,,4] of semaphore;

在這裏插入圖片描述

讀者寫者問題

問題

允許多個讀進程同時讀一個共享對象,因爲讀操作不會使數據文件混亂。但不允許一個Writer進程和其他Reader進程或Writer進程同時訪問共享對象。因爲這種訪問將會引起混亂。
在這裏插入圖片描述

記錄型信號量

爲實現Reader和Writer進程間在讀或寫時的互斥而設置了一個互斥信號量Wmutex。另外,再設置一個整型變量readcount表示正在讀的進程數目。

semaphore rmutex=1,wmutex=1;
int readcount=0;
void reader(){
            do  {
                    wait(rmutex);
                    if (readcount=0) wait(wmutex);
                       readcount++;
                    signal(rmutex);
                           …
                       perform read operation;wait(rmutex);
					readcount--;
					if (readcount=0) signal(wmutex);
					signal(rmutex);
					 }while(TRUE);
}
void writer() {
     do {
       wait(wmutex); 
       perform write operation;
       signal(wmutex);
     } while(TRUE);
  }
Void main() {
 cobegin
     reader();writer();
  coend;
}

只要有一個Reader進程在讀,便不允許Writer進程去寫。因此,僅當readcount=0,表示尚無Reader進程在讀時,Reader進程才需要執行wait(wmutex)操作;若wait(wmutex)操作成功,Reader進程便可去讀,相應地,做readcount+1操作。
同理,僅當Reader進程在執行了readcount減1操作後其值爲0時,才須執行signal(wmutex)操作,以便讓Writer進程寫。
Readcount是一個可被多個Reader進程訪問的臨界資源,因此,應該爲它設置一個互斥信號量rmutex。
在這裏插入圖片描述
在這裏插入圖片描述

信號量集

與前面的讀者-寫者問題不同,增加了一個限制,即最多隻允許RN個讀者同時讀。爲此,又引入了一個信號量L,並賦予其初值爲RN,通過執行wait(L,1,1)操作,來控制讀者的數目,每當有一個讀者進入時,就要先執行wait(L,1,1)操作,使L的值減1。當有RN個讀者進入讀後,L便減爲0,第RN+1個讀者要進入讀時,必然會因wait(L,1,1)操作失敗而阻塞。

int RN;
   semaphore   L=RN,mx=1;
Void reader() {
    do {
            Swait(L,1,1);
            //Swait(mx,1,0)語句起着開關的作用。只要無writer進程進入寫,mx=1,reader進程就都可以進入讀;一旦有writer進程進入寫時,其mx=0,則任何reader進程就都無法進入讀;
            Swait(mx,1,0);
                      …
           perform read operation;Ssignal(L,1);
      }while(TRUE);
}
void writer() {
    do {
    		//Swait(mx,1,1,L,RN,0)語句表示僅當既無writer進程在寫(mx=1),又無reader進程在讀(L=RN)時,writer進程才能進入臨界區寫。
            Swait(mx,1,1;L,RN,0);
			perform write operation;
			Ssignal(mx,1);
  }while(TRUE);
}
Void main() {
   cobegin
    reader();writer();
   coend;
  }

總結了快一個下午…好累
在這裏插入圖片描述

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