經典程序同步與互斥問題——生產者消費者問題
問題描述:生產者——消費者問題是指有兩組程序共享一個環形的緩衝池,一組稱為生產者,一組稱為消費者。緩衝池是由若干個大小相等的緩衝區組成,每個緩衝區可以容納一個產品。生產者程序不斷的將產品放入緩衝池中,消費者不斷將產品從緩衝池中取出。
核心:生產者——消費者問題,既存在著程序同步問題,也存在著臨界區互斥問題。當緩衝區滿時,表示供大於求,生產者必須停止生產,進入等待狀態,同時喚醒消費者;當所有緩衝區都為空時,表示供不應求,消費者必須停止消費,喚醒生產者。這就是生產者程序和消費者程序的同步關係。對於緩衝池,生產者和消費者都要使用它,顯然他是一個臨界資源,對於緩衝池的操作必須是互斥的。
這裡採用P、V操作解決生產者消費者問題的形式化描述
semaphore mutex=1; semaohore empty=n; semaphore full=0 //定義是3個訊號量 int i,j; ITEM buffer[n]; ITEM data_p,data_c; void producer() { while(true) { produce an item in data_p; P(empty); P(mutex); buffer[i]=data_p; i=(i+1)%n; V(mutex); V(full); } } void consumer() { while(true) { P(full); P(mutex); data_c=buffer[j]; j=(j+1)%n; V(mutex); V(empty); consume the item in data_c; } }
總結:
1.把共享緩衝池的n個緩衝區視為臨界資源,程序在使用時,首先要檢查是否有其他程序在臨界區,確認沒有時在進入。在程式中,P(mutex)和V(mutex)用於實現對臨界區的互斥,P(mutex)和V(mutex)必須成對出現。
2.訊號量full表示有資料的緩衝區的數目,初始值為0,empty表示空閒緩衝區的數目,初始值為n。他們表示的都是資源的數目,因此稱為資源訊號量。實際上,full和empty之間存在關係,full+empty=n。對資源訊號量的PV操作同樣需要成對出現,與互斥訊號量不同的是,P操作和V操作分別處於不同的程式中,例如P(empty)在生產者程序中,而V(empty)在消費者程序中。當生產者程序因執行P(empty)而阻塞時,由消費者程序的V(empty)將其喚醒;同理,當消費者程序因執行P(full)而阻塞時,生產者程序用V(full)將其喚醒。
思考:在生產者進行中的P(empty)和P(mutex)的位置能否互換?
顯然是不能的,如果交換後,就可能會發生死鎖。可以想象這種情況,生產者程序,執行P(mutex)進入臨界區,接下來執行P(empty),但現在empty為0,生產者被阻塞無法繼續生產,用時它又已經進入了臨界區,消費者進行由於無法進入臨界區,也被阻塞。這樣整個系統都被阻塞,發生死鎖現象。