基本概念
在信號量機制中,每個要訪問臨界資源的進程都必須自備同步的PV操作,大量分散的同步操作會給系統管理帶來麻煩,且容易因為同步操作不當而導致系統死鎖。於是便產生了一種新的進程同步工具——管程(Monitors)。
管程(Monitors):是一個資源管理模塊,其中包含了共享資源的數據結構,以及由對該共享數據結構實施操作的一組過程(方法)所組成的資源管理程序。
管程中包含條件變量,用於管理進程的阻塞和喚醒。其形式為 condition x;對它的操作僅有wait和signal。
x.wait:正在調用管程的進程因 x 條件需要被阻塞或掛起,則調用 x.wait 將自己插入到 x 條件的等待隊列上,並釋放管程,直到 x 條件變化。此時其它進程可以使用該管程。
x.signal:正在調用管程的進程發現 x 條件發生了變化,則調用 x.signal,重新啟動一個因 x 條件而阻塞或掛起的進程。(與信號量的signal不同,沒有s:=s+1的操作)
個人理解:
- 管程相當於把對臨界資源的操作封裝了起來,當進程要對資源進行操作時,只要調用管程中的方法就可以了,而不用進程自己擔心同步和互斥的問題,管程的內部有自己的一套機制進行同步與互斥。
- 管程中每次只允許一個進程進入管程。
- 當調用管程的進程因為某原因阻塞或者掛起時,把這個原因定義為一個條件變量x。
- x.wait操作就是把自己放到一個隊列上,這個隊列上的進程都是因為x原因而阻塞的。
- x.signal操作就是讓在x阻塞隊列上的一個進程重新啟動。
相對形象的比喻:假如一個管程叫ATM(取款機),其包含兩個方法:存款和取款,不同的人代表不同的進程,但是ATM只允許一個人在一個時間段中進行操作,當一個人在使用時,其他的人只能wait。此外,一個人如果使用的時間太長也不行,所以需要一個條件變量來約束他。
比如一個人在操作ATM時突然接電話了,沒法繼續操作,把這個原因記為x,執行x.wait,讓他離開ATM機,去接電話的隊列中等待。等到打完電話,即調用了x.signal后,他就可以繼續操作ATM了(一般令正在操作ATM的人操作完后,他才能重新進去)。
實際應用:
生產者-消費者問題
建立producer-consumer管程,其中包括兩個方法:
1.put(x):生產者利用該過程將自己生產的產品投放到緩沖池中,並用整型變量 count 來表示在緩沖池中已有的產品數目,當 count≥n 時,表示緩沖池已滿,生產者須等待。
2.get(x):消費者利用該過程從緩沖池中取出一個產品,當 count≤0 時,表示緩沖池中已無可取用的產品,消費者應等待。
兩個條件變量:notfull和notempty,代表進程阻塞原因
producer-consumer管程的描述:
type producer-consumer=monitor Var in,out,count: integer; buffer: array[0, …, n-1] of item; notfull,notempty:condition; //條件變量 procedure entry put(item) begin if count>=n then notfull.wait; //緩沖池已經滿了,生產者需要等待(我覺得命名為full可能更好,代表原因;不過也可以理解為:等到notfull才繼續執行) buffer(in):=nextp; in:=(in+1) mod n; count:=count+1; if notempty.queue then notempty.signal; //喚醒一個在notempty隊列中等待的進程 end procedure entry get(item) begin if count<=0 then notempty.wait; nextc:=buffer(out); out:=(out+1) mod n; count:=count - 1; if notfull.quene then notfull.signal; end begin in:=out:=0; count:=0 end
生產者-消費者的描述:
producer: begin repeat produce an item in nextp; PC.put(item); until false; end consumer: begin repeat PC.get(item); consume the item in nextc; until false; end
參考資料:《計算機操作系統(第三版)》(湯小丹等著)