進程同步
一、進程同步的基本概念
多道程序環境下,進程是並發執行的,不同進程間存在着不同的相互制約關系。為了協調進程之間的相互制約關系,達到資源共享和進程協作,避免進程之間的沖突,引入了進程同步的概念。
臨界資源
多個進程可以共享系統中的各種資源,但其中許多資源一次只能為一個進程所使用,我們把一次只允許一個進程使用的資源稱為臨界資源。
對臨界資源的訪問,必須互斥的進行。每個進程中,訪問臨界資源的那段代碼稱為臨界區。
為了保證臨界資源的正確使用,可以把臨界資源的訪問過程分為四個部分。
1) 進入區。為了進入臨界區使用臨界資源,在進入區要檢查可否進入臨界區。
2) 臨界區。進程中訪問臨界資源的那段代碼。
3) 退出區。將正在訪問臨界區的標志清除。
4) 剩余區。代碼中的其余部分。
do {
entry section;
critical section;
exit section;
remainder section;
}while (true)
同步
同步已成為直接制約關系,它是為完成某種任務而建立的兩個或多個進程。這些進程因為需要在某些位置上協調他們的工作次序而等待、傳遞信息所產生的制約關系。進程間的直接制約關系就是它們之間的相互合作。
互斥
互斥亦稱間接制約關系。當一個進程進入臨界區使用臨界資源時,另一個進程必須等待,當占用臨界資源的進程退出臨界區后,另一個進程才允許去訪問此臨界資源。
二、實現臨界區互斥的基本方法
在進入區設置和檢查一些標志來表名是否有進程在臨界區中,如果已有進程在臨界區,則在進入區通過循環檢查進行等待,進程離開臨界區后則在退出區修改標志。
硬件實現方法
本節對硬件實現的具體理解對后面的信號量學習很有幫助。計算機提供了特殊的硬件指令,允許對一個字中的內容進行檢測和修正,或者是對兩個字的內容進行交換等。通過硬件支持實現臨界段問題的低級方法或稱為元方法。
1) 中斷屏蔽方法。當一個進程正在使用處理器執行他的臨界區代碼時,要防止去其他進程在進入其臨界區訪問的最簡單方法就是禁止一切中斷的發生,或稱之為屏蔽中斷、關中斷。因為CPU只有在發生中斷時引起進程的調度和切換,這樣屏蔽中斷就能保證當前運行進程將臨界區代碼順利的執行完,然后再開中斷。
這種方法限制了處理器交替執行程序的能力,因此執行的效率將會明顯降低。對內核來說,當它執行更新變量或列表的幾條指令期間關中斷是很方便的,但將關中斷的權力交給用戶則很不明智,若一個進程關中斷之后不再打開終端,則系統可能會因此終止。
2) 硬件指令法
TestAndSet指令:這條指令是原子操作。及執行該代碼是不允許被中斷。其功能是獨處制定標志后把該標志設置為真。
Boolean TestAndSet( Boolean *lock){
Boolean old;
Old=*lock;
*lock=true;
Return old;
}
Lock為每個臨界資源設置的共享布爾變量,true表示正在被占用,false表示沒被占用。
While TestAndSet(&lock);
進程的臨界區代碼;
Lock=false;
進程剩余代碼;
Swap指令:該指令的功能是交換兩個字的內容。
Swap(Boolean a, Boolean b){
Boolean temp;
Temp= *a;
a=b;
*b=temp;
}
以上對TestAndSet和Swap指令僅僅是功能實現,並非軟件實現定義,事實上他們是由硬件邏輯直接實現的,不會被中斷。
硬件方法優點:使用與任意數目的進程,不管是單處理器還是多處理器:簡單、容易驗證其正確性。可以支持進程內有多個臨界區,只需要為每個臨界區設立一個布爾變量。
硬件方法的缺點:進程等待進入臨界區時要耗費處理器時間,不能實現讓權等待。從等待進程中隨機選擇一個進入臨界區,有的進程可能一直選不上,從而導致“飢餓”現象。
三、信號量
信號量機構是一種功能較強的機制,可用來解決互斥與同步的問題,它只能被兩個標准原語wait和signal來訪問,也可以記作p操作和v操作。原語是指完成某種功能且不被分割不被中斷執行的操作序列,有時也成為原子操作,通常可用硬件來實現完成某種功能的不可分割執行特性。
整形信號量
整形信號量被定義為一個用於表示資源個數的整型量S。
記錄性信號量
記錄性信號量是不存在“忙等”現象的進程同步機制。除了需要一個用於代表資源數的整型變量value外,再增加一個進程鏈表L,用於連接所有等待該資源的進程,記錄型信號量是由於采用了記錄型的數據結構得名。記錄型信號量可描述為:
Typedef struct{
Int value;
Struct process * L;
}semaphore;
Wait操作,表示進程請求一個該類資源,當S.value<0時,表示該類資源已分配完畢,因此進程調用block原語,進行自我阻塞,放棄處理器,並插入到S.L中,可見該機制遵循了“讓權等待”的原則。Signal 操作,表示進程釋放一個資源,使系統中可供分配資源數增加一,故S.value++。若加1后仍是S.value<=0,則表示S.L中仍有等待該資源的進程被阻塞,故還應調用wakeup原語,將S.L中的第一個等待進程喚醒。
利用信號量實現同步
信號量機構能用於解決進程間各種同步問題。
利用信號量實現互斥
信號量機構能很方便的解決進程互斥問題。
互斥的實現是不同進程對同一信號量進行P操作和V操作,一個進程在成功地對信號量執行了P操作后進入臨界區,並在退出臨界區后,由該進程本身對該信號量執行V操作,表示當前沒有進城進入臨界區,可讓其他進程進入。
利用信號量實現前驅關系
信號量也可以用來描述程序之間或者語句之間的前驅關系。
分析進程同步或互斥問題的方法步驟
1) 關系分析。找出問題中的進程數,並且分析它們之間的同步和互斥關系。同步、互斥、前去關系直接按照上面例子中的經典犯事改寫。
2) 整體思路。找出解決問題的關鍵點,並且根據做過的題目找出解決的思路。根據進程的操作流程確定P操作、V操作的大致順序。
3) 設置信號量。根據上面兩步,設置需要的信號量,確定初值,完善整理。
四、管程
管程是一組數據以及定義在這組數據之上的對這組數據的操作組成的軟件模塊,這組操作能初始化並改變管程中的數據和同步進程。
1) 局部與管程的共享結構數據說明
2) 對該數據結構進行操作的一組過程
3) 對局部於管程的共享數據設置初始值的語句
4)局部於管程的數據只能被局部於管程內的過程訪問。
5)一個進程只有通過調用管程內的過程才能進入廣成訪問的共享數據。
6)每次僅允許一個進程在管程內執行某個內部過程。
由於管程是一個語言成分,所以管程的互斥訪問完全由編譯程序在編譯時自動添加,無需程序員關注,而且保證正確。
五、經典同步問題
問題描述:一組生產者進程和一組消費者進程共享一個初始為空、大小為n的緩沖區,只有緩沖區沒滿時,生產者才能把消息放入到緩沖區,否則必須等待;只有緩沖區不為空時,消費者才能從中取出消息,否則必須等待。由於緩沖區是臨界資源,它只允許一個生產者放入消
息,或一個消費者從中取出消息。
問題分析:
1)關系分析。生產者和消費者對緩沖區互斥訪問是互斥關系,同時生產者和消費者又是一個相互協作的關系,只有生產者生產之后,消費者才能消費,他們也是同步關系。
2)整理思路。這里比較簡單,只有生產者和消費者兩個進程,正好是這兩個進程存在着互斥關系和同步關系。那么需要解決的是互斥和同步PV操作的位置。
3)信號量的設置。信號量mutex作為互斥信號量,它用於控制互斥訪問緩沖池,互斥信號量初始為1;信號量full用於記錄當前緩沖池中“滿”緩沖區數,初值為0.信號量empty用於記錄當前緩沖池中空緩沖區,初值為n。
下面再看一個較為復雜的生產者-消費者問題:
問題描述:桌子上有一只盤子,每次孩子能向其中放入一個水果。爸爸專向盤子中放入蘋果,媽媽專向盤子中放入橘子,女兒專等吃盤子中的蘋果,兒子專等吃盤子中的橘子。只有盤子為空時,爸爸或媽媽就可向盤子中放一只水果2;僅當盤子中有自己需要的水果時,兒子
或女兒可以從盤子中取出。
問題分析:
1)關系分析。這里的關系略微復雜一些,首先由每次只能向其中放入一只水果可知爸爸和媽媽是互斥關系。爸爸和女兒、媽媽和兒子是同步關系,而且這兩對進程必須連起來,兒子和女兒之間沒有互斥和同步關系,因為他們是選擇條件執行,不可能並發。
2)整理思路。這里有4個進程,實際上可以抽象為兩個生產者和兩個消費者被連接到大小為1的緩沖區上。
3)信號量設置。首先設置信號量plate為互斥信號量,表示是否允許向盤子放水果,初值為1,表示允許放入,且只允許放一只。信號量apple表示盤子里是否有蘋果,初值為0,表示盤子中無2蘋果;信號量orange表示盤子中是否有橘子,初始量為0,表示盤子中無橘子。
問題描述:有讀者和寫者兩組並發進程,共享一個文件,當兩個以上的讀進程同時訪問共享數據時不會產生副作用,但若某個寫進程和其他進程(讀進程或寫進程)同時訪問共享數據時則可能導致數據不一致的錯誤。因此要求:1)允許多個讀者同時對文件執行讀操作;2)
只允許一個寫者往文件中寫信息;3)任一寫者在完成寫操作之前不允許其他讀者或寫者工作;4)寫者執行完寫操作前,應讓已有的讀者或寫者全部退出。
問題分析:
1)關系分析。由題目分析讀者和寫者是互斥的,寫者和寫者也是互斥的,而讀者和讀者不存在互斥關系。
2)整理思路。兩個進程,即讀者和寫者。寫者比較簡凡,它和任何進程互斥,用互斥信號量p操作、v操作即可解決。讀者的問題比較復雜,它必須實現與寫着互斥的關系,還要實現和其他讀者同步的關系。因此,緊急簡單的一對pv操作時無法解決的。那么在這里用到了一個計數器,用它來判斷當前是否有讀者讀文件。當有讀者的時候,寫着是無法寫文件的,此時讀者會一直占用文件,當沒有讀者的時候,寫者才可以寫文件。同事這里不同讀者對計數器的訪問也是互斥的。
3)信號量的設置。首先設置信號量count為計數器,用來記錄當前讀者數量,初值為0;設置mutex為互斥信號量,用於保護更新count變量時的互斥;設置互斥信號量rw用於保證讀者和寫者的互斥訪問。
問題描述:一張圓桌上坐着五個哲學家,每兩個哲學家之間的桌子上擺着一根筷子,桌子的中間是一碗米飯。哲學家們傾注畢生精力用於思考和進餐,哲學家在思考是,並不影響其他人。只有當哲學家飢餓的時候,才視圖拿起左右兩根筷子。如果筷子已經在他人手上,則需
等待。飢餓的哲學家只有同時拿到了兩根筷子才可以開始進餐,當今參悟你比猴,放下筷子繼續思考。
問題分析:
1)關系分析。五個哲學家與左右鄰居對其中的筷子的訪問是互斥關系。
2)整理思路。顯然這五個進程,要解決的問題有兩個:一個是讓他們同時拿起兩個筷子;而是對每個哲學家的動作執行規則,避免飢餓或者死鎖現象發生。
3)信號量設置。定義互斥信號組chopsticks【5】={1,1,1,1,1}用於對五個筷子的互斥訪問。對哲學家按順序0~4編號,哲學家i左邊的筷子編號為i,哲學家右邊的筷子編號為(i+1)%5。
問題描述:假設一個系統有三個吸煙者進程和一個供應者進程。每個抽煙者不停的卷煙並抽調他,但是要卷起並抽掉一支煙,抽煙者必須要有三種材料:煙草、紙和膠水。三個抽煙者中,第一個有煙草,第二個有紙,第三個有膠水。供應者進程無線地提供提供三種材料。供應者每次將兩種材料放到桌子上,擁有剩下那種材料的抽煙者卷一根煙並抽掉它,並給供應者一個信號告訴完成了,供應者就會放另外兩種材料在桌子上,這種過程一直重復。
問題分析:
1)關系分析。供應者與三個抽煙者分別是同步關系。由於供應者無法同時滿足兩個或兩個以上的抽煙者,三個抽煙者對抽煙這個動作是互斥關系。
2)整理思路。顯然這里有四個進程。供應者作為生產者向三個抽煙者提供材料。
3)信號量設置。信號量offer1、offer2、offer3分別表示煙草和紙組合的資源、煙草和膠水組合的資源、紙和膠水組合的資源。信號量finish用於互斥進行抽煙動作。