進程與進程管理 | 進程同步機制
進程同步概念
- 概念:並發進程在一些關鍵點上可能需要互相等待或互通消息,這種相互制約的等待或互通消息稱為進程同步。
- 同步機制應遵循的準則
- 空閑讓進:其他進程均不處於臨界區;
- 忙則等待:已有進程處於其臨界區;
- 有限等待:等待進入臨界區的進程不能"死等";
- 讓權等待:不能進入臨界區的進程,應釋放CPU(如轉換到等待狀態)
使用軟體演算法實現互斥
- 演算法1:兩個進程P0, P1共享某臨界資源
- 演算法一:設立一個公用整型變數 turn,描述允許進入臨界區的進程標識,假設初始化turn=0,表示首先輪到P0訪問臨界資源
- 該演算法,初始化是設置的等待 P0 對進程進行訪問,但是如果 P1 先申請訪問就不能執行,違背了空閑讓進的準則。
- 當 turn 值為1時,如果 P0 進程想要訪問臨界資源,會在 while 語句中執行空循環等待,知道 turn 變為 0。所以當 P0 不能拿到訪問權時,並沒有放棄等待,而是一直占著 CPU 在做空循環等待,違背了讓權等待的準則。
- 演算法二:設立一個標誌數組flag[2]:描述進程是否已在臨界區,初值均為0(FALSE),表示進程都不在臨界區。
- 在這個演算法中,當 flag[1] = 0 的時候,我們可以進入 P0 進程,當 P0 進程剛執行完第一條 while 語句的時候,它的時間片到了, 中斷 P0 進程的執行,進而執行 P1 的時候,又會因為 flag[0] = 0,認為臨界資源可以訪問,這樣 P0 和 P1 都會同時訪問臨界資源。違背了忙則等待的原則
- 當 flag[1] 為 1 的時候,P0 進程的 while 語句會執行空循環等待,所以也違背了讓權等待的原則。
使用鎖機制實現互斥
- 鎖的定義:用變數w代表某種資源的狀態,w稱為「鎖」 。
- 上鎖操作和開鎖操作
- 上鎖操作(臨界資源的申請操作):
- 檢測w的值 (是0還是1);
- 如果w的值為1,繼續檢測;
- 如果w的值為0,將鎖位置1 (表示佔用資源),進入臨界區執行
- 開鎖操作(臨界資源的釋放操作):
- 臨界資源使用完畢,將鎖位置0
- 上鎖原語和開鎖原語
- 上鎖原語
lock(){ test: if (w為1) goto test; ∕* 測試鎖位的值*∕ else w=1;} ∕*上鎖*∕
- 開鎖原語
unlock(){ w=0;} ∕*開鎖*∕
- 操作方法
- 加鎖操作 -》 執行臨界區程序 -》 開鎖操作
信號量機制
- 信號量數據結構的定義
typedef struct{ int value; /*信號量的值*/ PCB * L; /*進程等待隊列隊首指針*/} semaphore ;
- value:初始化為一個非負整數值,表示空閑資源總數--若為非負值表示當前的空閑資源數,若為負值其絕對值表示當前等待臨界資源的進程個數。
- L:初值為空
- 信號量的P、V操作: semaphore *S;
- P 操作(臨界資源申請操作)
P(S){ S->value--; if(S->value<0) sleep(S->L); // 由於進程在不能申請到臨界資源時是主動釋放CPU並且阻塞到L鏈表上 // 所以信號量實現了讓權等待的機制}
- V 操作(臨界資源釋放操作)
V(S){ S->value++; // 歸還一個臨界資源給系統 if(S->value<=0) wakeup(S->L); // 喚醒進程}
利用信號量機制實現進程互斥與同步
- 實現互斥
- 為臨界資源設置一個互斥信號量 mutex ,其初值為 1:
semaphore mutex=1
- 在每個進程中將臨界區代碼置於P(mutex)和V(mutex)原語之間:
- 演算法描述如下:
- 給出一個例子:兩個進程共享一台印表機
- 在執行 Pa 進程的過程中,P 操作先對 mutex 減一,得到 0。不是負數,可以直接執行。 Pb 進程如果在這個時候進行申請,此時執行 P 操作,mutex 得到 -1,會阻塞 Pb 進程。
- 當執行 Pa 進程的 V 操作時, mutex 值為 -1,加 1 得到 0。小於等於 0,喚醒等待進程 Pb。
- 當 Pb 進程執行到 V 操作時, mutex 加 1 得到 1,此時印表機空閑。
- 實現同步:進程間合作的前驅後繼關係
- 為一個同步關係設置一個同步信號量S,其初值為0:
semaphore S=0 // 表示令牌
- 前驅進程完成操作後執行V(S):表示釋放令牌;後繼進程開始操作前執行P(S):表示申請令牌
- 演算法描述:Pa -> Pb
- 舉個例子: I -> C -> P
- 再舉一個例子:對給出的前驅圖編寫同步信號量程序:
a,b,c,d,e,f,g:semaphore=0,0,0,0,0,0,0cobegin s1: { s1; v(a); v(b);} s2: { p(a); s2; v(c); v(d);} s3: { p(b); s3; v(e); } s4: { p(c); s4; v(f); } s5: { p(d); s5; v(g); } s6: { p(e); p(f); p(g); s6; }coend
- 最後,再給出一個司機和售票員的例子,司機和售票員的工作進程如下:
- 我們,首先需要尋找這兩個進程之間的同步關係,得到同步關係如下:
- 售票員關閉車門→ 司機啟動車輛
- 司機到站停車→ 售票員打開車門
- 對於這連個同步關係,我們設置相應的同步信號量如下:
- semaphore drive_sem={0,NULL};
- semaphore conductor_sem={0,NULL};
- 最後,我們根據這些信號量的設置,寫出相應的演算法如下:
- 使用信號量解決進程同步問題的步驟
- 確定進程:
- 包括進程的數量、進程的工作內容。
- 確定進程同步互斥關係:
- 根據進程間是競爭臨界資源還是相互合作處理上的前後關 系,來確定進程間是互斥還是同步。
- 確定信號量:
- 根據進程間的同步互斥關係確定信號量個數、含義、初始值,各進程需要對信號量進行的PV操作。
- 用類程序語言描述演算法。
推薦閱讀:
※提高 Linux 開發效率的 5 個工具
※進程與進程管理 | 經典進程同步問題
※操作系統精髓與設計原理讀書筆記7內存管理,虛擬內存
※操作系統引論 | 操作系統的地位和作用
※一個Mac小白的自我修養
TAG:操作系統 |