學會程序同步,有這一篇就夠了
同步速度什麼意思
為什麼要有程序同步
直接談程序同步的概念有點抽象,我們先聊一聊為什麼要有程序同步機制。 我們的計算機系統剛開始是單道批處理系統,意思就是同一時間段內只能執行一個程式,這個程式執行完,才能執行另一個程式,這樣就會導致執行效率太低,系統中的資源得不到充分的利用。 怎麼解決呢,就發明了多道批處理系統,多道程式併發執行,這樣大大提高了系統資源的利用率。 但是這種系統就會產生一些問題,比如有的資源,比如顯示器,cpu,同一時間肯定只能一個程式使用,多個程式肯定不能同時使用顯示器,這就是
「互斥關係」
,另外,有的兩個程序間存在這樣的制約關係:A程式的輸出是B程式的輸入,這是
「同步關係」
,為了解決這些問題,我們引入了程序同步機制。
程序同步的方法
怎麼用程序同步的方法解決上述問題呢,其中一個方法就是訊號量機制。
訊號量機制
訊號量機制是由荷蘭的dijkstra發明的,有三種訊號量機制,分別是
「整型訊號量」
,
「結構體型訊號量」
和
「AND型訊號量」
。
「整型訊號量」
說白了就是用一個整數來進行管理,這個整數代表資源的數目,眾所周知,對資源的操作有兩種,一種是使用,一種是釋放。 他們分別對應兩個函式:wait和signal
wait(S){
while(S<=0);
S——;
}
signal(S){
S++;
}
wait方法的意思就是首先看資源可不可以用,如果不可以用,也就是S<=0,它會一直等下去,直到S成為一個正數,然後S自減;signal的意思是使用完資源後釋放資源,S自增。
「結構體型訊號量」
為什麼整型訊號量用的好好的,要造一個結構體型訊號量呢? 因為整型訊號量有個問題:我們會發現當S<=0的時候,會一直執行迴圈,也就是程序會處於忙等的狀態。 我們要解決忙等,也就是要讓程序符合“讓權等待”,就是要在程序無法使用資源的時候,釋放處理機。 那麼問題就來了,該讓哪個程序訪問臨界資源呢? 我們可以使用一個連結串列來解決這個問題。 所以我們就用一個結構體來描述資源,這個結構體長這樣:
typedef struct{
int value;
struct process_control_block *list;
}semaphore;
這個結構體裡邊有兩個變數,一個是value,用來記錄資源的個數,下邊這個是指標,指向下一個要使用臨界資源的程序。 所以之前的使用和釋放資源的函式就變成了這樣:
wait(semaphore *S){
S->value——;
if(S->value<0) block(S->list);
}
signal(semaphore *S){
s->value++;
if(S->value<=0) wakeup(S->list);
}
使用訊號量機制解決問題
上邊咱們只是簡單介紹了一下訊號量機制,但別忘了咋們是要解決互斥關係和同步關係這兩個問題的。
「實現互斥關係」
假設兩個程序PA,PB具有互斥關係,也就是他們倆要使用一個臨界資源,怎麼做呢,我們設定一個mutex訊號量,初值設為1,這樣的話剛開始兩個程序都能使用,他們使用的時候,先wait,wait完自然要讓mutex-1,這樣mutex為0,另一個就不能用了,使用完以後signal(釋放),mutex重新變成1,另一個程序依然可以使用該臨界資源。
semaphore mutex=1;
PA(){
while(1){
wait(mutex);
臨界區
signal(mutex);
剩餘區
}
}
PB(){
while(1){
wait(mutex);
臨界區
signal(mutex);
剩餘區
}
}
「實現前驅關係」
假設P1和P2有前驅關係,P1執行完,P2才能執行,那麼怎麼實現呢? 可以設定一個公共的訊號量S,初值設為0
程序P1中:S1;signal(S);
程序P2中:wait(S);S2;
這個是什麼意思呢,就是先執行P1的語句,然後釋放S,也就是S++,這樣當P2執行wait的時候才可以執行,否則,不執行signal的話,S就為0,P2也無法執行,這樣就實現了P1和P2的前驅關係。