一、進程的互斥:
1.定義
比如一臺計算機連着一臺打印機,而且現在有多個打印進程,都想要進行打印,但是打印機不可能進行多個打印進程(如果這樣做就亂套了),所以這些打印進程之間就存在着一種互斥關係,這時候 打印機可以被看成一種臨界資源,在某個時刻內只能有一個進程佔用這個臨界資源,等這個進程結束,打印機資源才被釋放,其他的進程才能使用這個臨界資源
2.實現進程互斥的方法
因爲打印機屬於臨界資源,所以可以用互斥信號量mutex表示,而且打印機只有一臺,所以可以令mutex=1。
/*信號量機制實現互斥*/ semaphore mutex=1//定義並初始化信號量 P1(){ ... P(mutex); //使用臨界資源前需要加鎖 臨界代碼段.. V(mutex); //使用臨界資源後需要解鎖 ... } P2(){ ... P(mutex); //使用臨界資源前需要加鎖 臨界代碼段.. V(mutex); //使用臨界資源後需要解鎖 ... }
注:P,V操作就是 wait 和 signal 操作。wait 和 signal 是一對原語,可以把原語理解成我們自己寫的函數,函數名爲 wait
和 signal ,括號裏面的信號量其實就是函數調用時傳入的一個參數。
wait和signal函數原型:點擊這裏!!!
這裏面有一點要注意,假設現在正在進行P1進程的P(mutex); 執行完這一行說不定就切換進程就去執行其他進程去了,原因可能是進程調度的方式不同,可能該進程的時間片用完了或者他的原因(原因有多種,這裏只是說的一種可能情況)
二、進程的同步
1.定義
要讓各併發按照要求有序的推進。
P1(){ 代碼1; 代碼2; 代碼3; } P2(){ 代碼4; 代碼5; 代碼6; }
比如上面的P1,P2進程併發執行,由於存在異步性,因此二者交替推進的次序是不確定的(可能會發生中途切換進程的情況)
但有時候我們會要求一定的順序,比如(c=a+b;)執行這個代碼之前要求我們首先計算出a和b的值,再去計算c的值。再比如上面的P1,P2進程,我們要求代碼4要基於代碼的程序運行,那麼我們就要保證代碼4一定實在代碼2之後纔會執行
這就是所謂的進程同步問題,讓本來異步併發的進程互相配合,有序推進
2.實現進程同步的方法
用信號量實現進程同步:
1.分析爲什麼要實現”同步關係“,即必須保證”一前一後“執行的兩個操作(或兩句代碼)
2.設置同步信號量S,初始值爲0
3.在實現 ”前操作“之後執行 V(S) ------- signal 的加操作
4.在實現 ”後操作“之前執行 P(S) --------wait 的 減操作
還是上面的P1 ,P2進程,要求還是代碼4要在代碼2執行之後再執行,利用下面的方法即可實現
/*信號量機制實現同步*/ semaphore S=0; //初始化同步信號量 P1(){ 代碼1; 代碼2; V(S); 代碼3; } P2(){ P(S); 代碼4; 代碼5; 代碼6; }
分析:
情況一:若先執行到V(S) 操作,則S++後,S=1,之後執行到P(S)操作時,由於S=1,表示用可用的資源,會執行S--,
S的值變回到0,P2進程不會執行block原語,而是繼續往下執行代碼4。符合題意
情況二:若先執行到P(S)操作,由於S=0,S--後,表示此時沒有可用資源,因此P操作中會執行block原語,主動請求阻塞,之後當執行完代碼2,繼而執行V(S)操作,S++,使S變回到0,由於此時又進程在該信號量的阻塞隊列中,因此會在V操作中執行wakeup原語,喚醒P2進程,這樣P2進程就可以繼續執行代碼4了。符合題意
上面兩種情況保證了代碼4執行前代碼2肯定已經執行了