在學習進程互斥中,有個著名的問題:生產者-消費者問題。這個問題是一個標準的、著名的同時性編程問題的集合:一個有限緩衝區和兩類線程,它們是生產者和消費者,生產者把產品放入緩衝區,相反消費者便是從緩衝區中拿走產品。
生產者在緩衝區滿時必須等待,直到緩衝區有空間才繼續生產。消費者在緩衝區空時必須等待,直到緩衝區中有產品才能繼續讀取。
在這個問題上主要考慮的是:緩衝區滿或緩衝區空以及競爭條件(race condition)。以下是一個含競爭條件的生產者-消費者問題實例。
#define N 100 /*number of slots in the buffer*/
int count=0; /*number of items in the buffer*/
void producer(void) {
int item;
while(TRUE) {
produce_item(&item);
if (count==N) sleep();
enter_item(item);
count=count+1;
if (count==1) wakeup(consumer);
}
}
void comsumer(void) {
int item;
while(TRUE) {
if(count==0) sleep();
remove_item(&item);
count=count-1;
if (count==N-1) wakeup(producer);
consume_item(item);
}
}
在這個實例中,首先定義了一個大小爲100的公共緩衝區,也就是臨界資源,然後的count便是緩衝區中產品的數目,初始化爲0。producer函數是生產者函數,produce_item(&item);是指生產者生產出來一個產品,但是這時候並沒有對緩衝區進行操作。而if (count==N) sleep();是測試語句,如果生產出來的產品數和緩衝區大小相等時,生產者就進入睡眠狀態。如果不等,產品就放入緩衝區內,並且產品數增加1。if (count==1) wakeup(consumer);這條語句看上去讓人十分費解,其實它的意思是,如果上一次操作時產品的數目爲0,消費者已經進入了睡眠狀態,而現在生產者又生產出來一個產品,緩衝區內不爲空,這時把消費者喚醒。消費者函數也是同樣的道理,只不過一個是取,另一個是放。
我們可以看到,這裏存在潛在的競爭條件,所謂競爭條件就是這樣一種情況:多個線程對數據產生的作用要依賴於線程的調度順序的。當兩個線程競相訪問同一數據時,就會發生競爭條件。由於時間片的原因,一個線程可以在任意一個時刻打斷其他線程,因此數據可能會被破壞或者被錯誤地解釋。在這個實例上反應的結果是,生產者和消費者兩個進程都永遠睡眠。