臨界資源互斥的基本方法
阿新 • • 發佈:2019-02-13
轉自:http://see.xidian.edu.cn/cpp/html/2597.html
軟體實現方法
在進入區設定和檢查一些標誌來標明是否有程序在臨界區中,如果已有程序在臨界區,則在進入區通過迴圈檢查進行等待,程序離開臨界區後則在退出區修改標誌。1) 演算法一:單標誌法。
該演算法設定一個公用整型變數turn,用於指示被允許進入臨界區的程序編號,即若turn=0,則允許P0程序進入臨界區。該演算法可確保每次只允許一個程序進入臨界區。但兩個程序必須交替進入臨界區,如果某個程序不再進入臨界區了,那麼另一個程序也將進入臨界區(違背“空閒讓進”)這樣很容易造成資源利用的不充分。- // P0程序
- while(
- criticalsection;
- turn=1;
- remaindersection;
- // P1程序
- while(turn!=1); // 進入區
- criticalsection; // 臨界區
- turn = 0; // 退出區
- remaindersection; // 剩餘區
2) 演算法二:雙標誌法先檢查。
該演算法的基本思想是在每一個程序訪問臨界區資源之前,先檢視一下臨界資源是否正被訪問,若正被訪問,該程序需等待;否則,程序才進入自己的臨界區。為此,設定了一個數據flag[i],如第i個元素值為FALSE,表示Pi程序未進入臨界區,值為TRUE,表示Pi程序進入臨界區。- // Pi 程序
- while(flag[j]); // ①
- flag[i]=TRUE; // ③
- criticalsection;
- flag[i] = FALSE;
- remaindersection;
- // Pj 程序
- while(flag[i]); // ② 進入區
- flag[j] =TRUE; // ④ 進入區
- criticalsection; // 臨界區
- flag[j] = FALSE; // 退出區
- remaindersection; // 剩餘區
優點:不用交替進入,可連續使用;缺點:Pi和Pj可能同時進入臨界區。按序列①②③④ 執行時,會同時進入臨界區(違背“忙則等待”)。即在檢查對方flag之後和切換自己flag 之前有一段時間,結果都檢查通過。這裡的問題出在檢查和修改操作不能一次進行。
3) 演算法三:雙標誌法後檢查。
- // Pi程序
- flag[i] =TRUE;
- while(flag[j]);
- criticalsection;
- flag[i] =FLASE;
- remaindersection;
- // Pj程序
- flag[j] =TRUE; // 進入區
- while(flag[i]); // 進入區
- criticalsection; // 臨界區
- flag [j] =FLASE; // 退出區
- remaindersection; // 剩餘區
當兩個程序幾乎同時都想進入臨界區時,它們分別將自己的標誌值flag設定為TRUE,並且同時檢測對方的狀態(執行while語句),發現對方也要進入臨界區,於是雙方互相謙讓,結果誰也進不了臨界區,從而導致“飢餓”現象。
4)演算法四:Peterson’s Algorithm。
為了防止兩個程序為進入臨界區而無限期等待,又設定變數turn,指示不允許進入臨界區的程序編號,每個程序在先設定自己標誌後再設定turn 標誌,不允許另一個程序進入。這時,再同時檢測另一個程序狀態標誌和不允許進入標誌,這樣可以保證當兩個程序同時要求進入臨界區,只允許一個程序進入臨界區。- // Pi程序
- flag[i]=TURE; turn=j;
- while(flag[j]&&turn==j);
- criticalsection;
- flag[i]=FLASE;
- remaindersection;
- // Pj程序
- flag[j] =TRUE;turn=i; // 進入區
- while(flag[i]&&turn==i); // 進入區
- criticalsection; // 臨界區
- flag[j]=FLASE; // 退出區
- remaindersection; // 剩餘區
本演算法的基本思想是演算法一和演算法三的結合。利用flag解決臨界資源的互斥訪問,而利用turn解決“飢餓”現象。
硬體實現方法
本節對硬體實現的具體理解對後面的訊號量的學習很有幫助。計算機提供了特殊的硬體指令,允許對一個字中的內容進行檢測和修正,或者是對兩個字的內容進行交換等。通過硬體支援實現臨界段問題的低階方法或稱為元方法。1) 中斷遮蔽方法
當一個程序正在使用處理機執行它的臨界區程式碼時,要防止其他程序再進入其臨界區訪問的最簡單方法是禁止一切中斷髮生,或稱之為遮蔽中斷、關中斷。因為CPU只在發生中斷時引起程序切換,這樣遮蔽中斷就能保證當前執行程序將臨界區程式碼順利地執行完,從而保證了互斥的正確實現,然後再執行開中斷。其典型模式為:…
關中斷;
臨界區;
開中斷;
…
這種方法限制了處理機交替執行程式的能力,因此執行的效率將會明顯降低。對核心來說,當它執行更新變數或列表的幾條指令期間關中斷是很方便的,但將關中斷的權力交給使用者則很不明智,若一個程序關中斷之後不再開中斷,則系統可能會因此終止。
2) 硬體指令方法
TestAndSet指令:這條指令是原子操作,即執行該程式碼時不允許被中斷。其功能是讀出指定標誌後把該標誌設定為真。指令的功能描述如下:- booleanTestAndSet(boolean*lock){
- booleanold;
- old = *lock;
- *lock=true;
- return old;
- }
可以為每個臨界資源設定一個共享布林變數lock,表示資源的兩種狀態:true表示正被佔用,初值為false。在程序訪問臨界資源之前,利用TestAndSet檢查和修改標誌lock;若有程序在臨界區,則重複檢查,直到程序退出。利用該指令實現程序互斥的演算法描述如下:
- while TestAndSet (& 1 ock);
- // 程序的臨界區程式碼段;
- lock=false;
- // 程序的其他程式碼
Swap指令:該指令的功能是交換兩個位元組的內容。其功能描述如下。
- Swap(boolean*a, boolean*b){
- booleantemp;
- Temp=*a;
- *a = *b;
- *b = temp;
- }
注意:以上對TestAndSet和Swap指令的描述僅僅是功能實現,並非軟體實現定義,事實上它們是由硬體邏輯直接實現的,不會被中斷。
應為每個臨界資源設定了一個共享布林變數lock,初值為false;在每個程序中再設定一個區域性布林變數key,用於與lock交換資訊。在進入臨界區之前先利用Swap指令交換lock 與key的內容,然後檢查key的狀態;有程序在臨界區時,重複交換和檢查過程,直到程序退出。利用Swap指令實現程序互斥的演算法描述如下:
- key=true;
- while(key!=false)
- Swap(&lock, &key);
- // 程序的臨界區程式碼段;
- lock=false;
- // 程序的其他程式碼;
硬體方法的優點:適用於任意數目的程序,不管是單處理機還是多處理機;簡單、容易驗證其正確性。可以支援程序內有多個臨界區,只需為每個臨界區設立一個布林變數。
硬體方法的缺點:程序等待進入臨界區時要耗費處理機時間,不能實現讓權等待。從等待程序中隨機選擇一個進入臨界區,有的程序可能一直選不上,從而導致“飢餓”現象。