第2篇 進程同步

聲明:本博客爲學習操作系統時所做筆記,主要資料來源爲《操作系統概念》(第七版)以及“C語言中文網”中的操作系統篇,如有不妥之處,再修改或者刪除。“C語言中文網址”如下:

http://c.biancheng.net/cpp/u/xitong/

1 進程同步

1.1 臨界資源

臨界資源概念:一次僅允許一個進程使用的資源稱爲臨界資源。對臨界資源的訪問,必須互斥地進行,在每個進程中,訪問臨界資源的那段代碼稱爲臨界區。

臨界資源的訪問過程分成四個部分:

①進入區:爲了進入臨界區使用臨界資源,在進入區要檢查可否進入臨界區,如果可以進入臨界區,則應設置正在訪問臨界區的標誌,以阻止其他進程同時進入臨界區。

②臨界區:進程中訪問臨界資源的那段代碼,又稱臨界段。

③退出區:將正在訪問臨界區的標誌清除。

④剩餘區:代碼中的其餘部分。

臨界區文體的解答必須滿足三項要求:互斥、前進、有限等待。

同步:同步亦稱直接制約關係,它是指爲完成某種任務而建立的兩個或多個進程,這些進程因爲需要在某些位置上協調它們的工作次序而等待、傳遞信息所產生的制約關係。

互斥:互斥亦稱間接制約關係。當一個進程進入臨界區使用臨界資源時,另一個進程必須等待, 當佔用臨界資源的進程退出臨界區後,另一進程才允許去訪問此臨界資源。

1.2 臨界區問題的解答

軟件實現方法:

1) 算法一:單標誌法。

優點:該算法可確保每次只允許一個進程進入臨界區。

缺點:兩個進程必須交替進入臨界區,如果某個進程不再進入臨界區了,那麼另一個進程也將無法進入臨界區(違背“空閒讓進”)這樣很容易造成資源利用的不充分。

// P0進程
while(turn!=0);
critical section;
turn=1;
remainder section;

// P1進程
while(turn!=1);  // 進入區
critical section;  // 臨界區
turn = 0;  // 退出區
remainder section;  // 剩餘區

2)算法二:雙標誌法先檢查。

優點:不用交替進入,可連續使用;

缺點:Pi和Pj可能同時進入臨界區。按序列①②③④ 執行時,會同時進入臨界區(違背“忙則等待”)。

// Pi 進程
while(flag[j]);  // ①
flag[i]=TRUE;  // ③  
critical section;   
flag[i] = FALSE; 
remainder section;

// Pj 進程
while(flag[i]);  // ② 進入區
flag[j] =TRUE;  // ④ 進入區
critical section;  // 臨界區
flag[j] = FALSE;  // 退出區
remainder section;  // 剩餘區

3) 算法三:雙標誌法後檢查。

缺點:當兩個進程幾乎同時都想進入臨界區時,它們分別將自己的標誌值flag設置爲TRUE,並且同時檢測對方的狀態(執行while語句),發現對方也要進入臨界區,於是雙方互相謙讓,結果誰也進不了臨界區,從而導致“飢餓”現象。

// Pi進程
flag[i] =TRUE;
while(flag[j]);
critical section;
flag[i] =FLASE;
remainder section;

// Pj進程
flag[j] =TRUE;  // 進入區
while(flag[i]);  // 進入區
critical section;  // 臨界區
flag [j] =FLASE;   // 退出區
remainder section;  // 剩餘區

4)算法四:Peterson’s Algorithm。

基本思想是算法一和算法三的結合。利用flag解決臨界資源的互斥訪問,而利用turn解決“飢餓”現象。

// Pi進程
flag[i]=TURE; turn=j;
while(flag[j]&&turn==j); 
critical section;
flag[i]=FLASE;
remainder section;

// Pj進程
flag[j] =TRUE;turn=i;  // 進入區
while(flag[i]&&turn==i);   // 進入區
critical section;  // 臨界區
flag[j]=FLASE;  // 退出區
remainder section;  // 剩餘區

硬件實現方法

許多現代操作系統提供了特殊硬件指令以允許原子地(不可中斷地)檢查和修改字的內容或交換兩個字的內容。

TestAndSet指令:這條指令是原子操作,即執行該代碼時不允許被中斷。其功能是讀出指定標誌後把該標誌設置爲真。

Swap指令:該指令的功能是交換兩個字節的內容。

硬件方法的優點:適用於任意數目的進程,不管是單處理機還是多處理機;簡單、容易驗證其正確性。可以支持進程內有多個臨界區,只需爲每個臨界區設立一個布爾變量。

硬件方法的缺點:進程等待進入臨界區時要耗費處理機時間,不能實現讓權等待。從等待進程中隨機選擇一個進入臨界區,有的進程可能一直選不上,從而導致“飢餓”現象。

1.3 信號量(semaphore)

信號量(S)是個整數變量,除此初始化之外,它只能通過兩個標準原子操作:wait()和signal()來訪問。

通常操作系統將信號量分爲二進制信號量計數信號量

wait() {                    
    while(S <= 0);
    S--;
}

signal() {
    S++;
}

1)用法:解決互斥問題。

二進制信號量可以被用來解決多進程的臨界區問題,n個進程共享一個信號量mutex,並初始化爲1。每個進程的結構如下:

do {
    wait(mutex);
        //critical section
    signal(mutex);
        //remainder section
}while(TRUE);

計數信號量可以用來控制訪問若干實例的某種資源,該信號量初始化爲可用資源的數量。

2)用法:解決同步問題。

例如:有兩個併發進程:P1有語句S1而P2有語句S2,假設要求S1執行完後在執行S2。則使P1和P2共享一個共同信號量synch,並初始化爲0。

//進程P1插入語句
S1;
signal(synch);
//進程P2插入語句
wait(synch);
S2;

信號量的關鍵之處是它們能原子的執行。必須確保沒有兩個進程能對對一信號量執行操作wait()和signal()。在單處理器環境下,可以在執行wait()和signal()操作時簡單地禁止中斷。多處理器環境下,必須禁止每個處理器的中斷,但是這比較困難,所以,SMP系統必須提供其他加鎖技術(如自旋鎖),確保wait()和signal()原子執行

3)分析進程同步和互斥問題的方法步驟

①關係分析。找出問題中的進程數,並且分析它們之間的同步和互斥關係。同步、互斥、前驅關係直接按照上面例子中的經典範式改寫。

②整理思路。找出解決問題的關鍵點,並且根據做過的題目找出解決的思路。根據進程的操作流程確定P操作、V操作的大致順序。

③設置信號量。根據上面兩步,設置需要的信號量,確定初值,完善整理。

1.4 死鎖和飢餓

死鎖(deallocked):兩個或多個進程無限等待一個事件,該事件只能由這些等待的進程之一來產生。

例如:兩個進程P0和P1組成的系統,每個都訪問共享信號量S和Q,這兩個信號量初值都爲1:

    P0                  P1
wait(S);            wait(Q);
wait(Q);            wait(S);
    .                   .
    .                   .
    .                   .
signal(S);          signal(Q);
signal(Q);          signal(S);

若出現如下執行順序,則發生死鎖:P0:wait(S)->P1:wait(Q)->P0:wait(Q)->P1->wait(S)。

1.5 經典同步問題

1)生產者-消費者問題(有限緩衝問題)

http://c.biancheng.net/cpp/html/2600.html

2)讀者-寫者問題

http://c.biancheng.net/cpp/html/2601.html

3)哲學家進餐問題

http://c.biancheng.net/cpp/html/2602.html

4)吸菸者問題

http://c.biancheng.net/cpp/html/2603.html

1.6 管程

管程:是由一組數據以及定義在這組數據之上的對這組數據的操作組成的軟件模塊,這組操作能初始化並改變管程中的數據和同步進程。

管程類型提供了一組由程序員定義的、在管程內互斥的操作。由於管程是一個語言成分,所以管程的互斥訪問完全由編譯程序在編譯時自動添加,無需程序員關注,而且保證正確。

發佈了54 篇原創文章 · 獲贊 14 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章