###問題描述
一組生產者進程和一組消費者進程共享一個初始為空、大小為n的緩沖區,只有緩沖區沒滿時,生產者才能把消息放入到緩沖區,否則必須等待;只有緩沖區不空時,消費者才能從中取出消息,否則必須等待。由于緩沖區是臨界資源,它只允許一個生產者放入消息,或者一個消費者從中取出消息。
###問題分析
1) 關系分析。生產者和消費者對緩沖區互斥訪問是互斥關系,同時生產者和消費者又是一個相互協作的關系,只有生產者生產之后,消費者才能消費,他們也是同步關系。
2) 整理思路。這里比較簡單,只有生產者和消費者兩個進程,正好是這兩個進程存在著互斥關系和同步關系。那么需要解決的是互斥和同步PV操作的位置。
3) 信號量設置。信號量mutex作為互斥信號量,它用于控制互斥訪問緩沖池,互斥信號量初值為1;信號量full用于記錄當前緩沖池中“滿”緩沖區數,初值為0。信號量empty 用于記錄當前緩沖池中“空”緩沖區數,初值為n。
生產者-消費者進程的描述如下:
~~~
semaphore mutex=1; //臨界區互斥信號量
semaphore empty=n; //空閑緩沖區
semaphore full=0; //緩沖區初始化為空
producer () { //生產者進程
while(1){
produce an item in nextp; //生產數據
P(empty); //獲取空緩沖區單元
P(mutex); //進入臨界區.
add nextp to buffer; //將數據放入緩沖區
V(mutex); //離開臨界區,釋放互斥信號量
V(full); //滿緩沖區數加1
}
}
consumer () { //消費者進程
while(1){
P(full); //獲取滿緩沖區單元
P(mutex); // 進入臨界區
remove an item from buffer; //從緩沖區中取出數據
V (mutex); //離開臨界區,釋放互斥信號量
V (empty) ; //空緩沖區數加1
consume the item; //消費數據
}
}
~~~
該類問題要注意對緩沖區大小為n的處理,當緩沖區中有空時便可對empty變量執行P 操作,一旦取走一個產品便要執行V操作以釋放空閑區。對empty和full變量的P操作必須放在對mutex的P操作之前。如果生產者進程先執行P(mutex),然后執行P(empty),消費者執行P(mutex),然后執行P(fall),這樣可不可以?答案是否定的。設想生產者進程已經將緩沖區放滿,消費者進程并沒有取產品,即empty = 0,當下次仍然是生產者進程運行時,它先執行P(mutex)封鎖信號量,再執行P(empty)時將被阻塞,希望消費者取出產品后將其喚醒。輪到消費者進程運行時,它先執行P(mutex),然而由于生產者進程已經封鎖mutex信號量,消費者進程也會被阻塞,這樣一來生產者、消費者進程都將阻塞,都指望對方喚醒自己,陷入了無休止的等待。同理,如果消費者進程已經將緩沖區取空,即 full = 0,下次如果還是消費者先運行,也會出現類似的死鎖。不過生產者釋放信號量時,mutex、full先釋放哪一個無所謂,消費者先釋放mutex還是empty都可以。
下面再看一個較為復雜的生產者-消費者問題:
###問題描述
桌子上有一只盤子,每次只能向其中放入一個水果。爸爸專向盤子中放蘋果,媽媽專向盤子中放橘子,兒子專等吃盤子中的橘子,女兒專等吃盤子中的蘋果。只有盤子為空時,爸爸或媽媽就可向盤子中放一個水果;僅當盤子中有自己需要的水果時,兒子或女兒
可以從盤子中取出。
###問題分析
1) 關系分析。這里的關系稍復雜一些,首先由每次只能向其中放入一只水果可知爸爸和媽媽是互斥關系。爸爸和女兒、媽媽和兒子是同步關系,而且這兩對進程必須連起來,兒子和女兒之間沒有互斥和同步關系,因為他們是選擇條件執行,不可能并發,如圖2-8所示。
2) 整理思路。這里有4個進程,實際上可以抽象為兩個生產者和兩個消費者被連接到大小為1的緩沖區上。

圖2-9 進程之間的關系
3) 信號量設置。首先設置信號量plate為互斥信號量,表示是否允許向盤子放入水果,初值為1,表示允許放入,且只允許放入一個。信號量 apple表示盤子中是否有蘋果,初值為0,表示盤子為空,不許取,若apple=l可以取。信號量orange表示盤子中是否有橘子,初值為0,表示盤子為空,不許取,若orange=l可以取。解決該問題的代碼如下:
~~~
semaphore plate=l, apple=0, orange=0;
dad() { //父親進程
while (1) {
prepare an apple;
P(plate) ; //互斥向盤中取、放水果
put the apple on the plate; //向盤中放蘋果
V(apple); //允許取蘋果
}
}
mom() { // 母親進程
while(1) {
prepare an orange;
P(plate); //互斥向盤中取、放水果
put the orange on the plate; //向盤中放橘子
V(orange); //允許取橘子
}
}
son(){ //兒子進程
while(1){
P(orange) ; //互斥向盤中取橘子
take an orange from the plate;
V(plate); //允許向盤中取、放水果
eat the orange;
}
}
daughter () { //女兒進程
while(1) {
P(apple); // 互斥向盤中取蘋果
take an apple from the plate;
V(plate); //運行向盤中取、放水果
eat the apple;
}
}
~~~
進程間的關系如圖2-9所示。dad()和daughter()、mam()和son()必須連續執行,正因為如此,也只能在女兒拿走蘋果后,或兒子拿走橘子后才能釋放盤子,即V(plate)操作。
- 1. 操作系統概述
- 2.操作系統(計算機)進程和線程管理
- 2.1 進程的概念和特征
- 2.2 進程的狀態與轉換
- 2.3 進程控制
- 2.4 進程的組
- 2.5 進程的通信
- 2.6 線程的概念和多線程模型
- 2.7 處理機調度
- 2.8 操作系統典型調度算法
- 2.9 進程同步的基本概念
- 2.10 實現臨界區互斥的基本方法
- 2.11 信號量
- 2.12 管程:管程的定義、組成及基本特性
- 2.13 經典進程同步問題1
- 2.14 經典進程同步問題2:讀者-寫者問題
- 2.15經典進程同步問題3:哲學家進餐問題
- 2.16 經典進程同步問題4:吸煙者問題
- 2.17 死鎖的概念以及產生死鎖的原因
- 2.18 關于進程和線程的知識點匯總