1. 程式人生 > >作業系統-程序通訊

作業系統-程序通訊

競爭條件
兩個或多個程序讀寫某些共享資料,而最後的結果取決於程序執行的精確時序,稱為競爭條件。凡涉及到資源的共享時就容易發生這樣的事情。解決的辦法是設立臨界區,讓程序互斥地訪問共享資源。一個好的避免競爭條件的方案,必須滿足4個條件:
任何兩個程序不能同時處於臨界區。
不應對CPU的速度和數量做任何假設。
臨界區外執行的程序不得阻塞其它程序。
不得讓程序無限期等待進入臨界區。

忙等待互斥
1.遮蔽中斷
程序在進入臨界區時遮蔽中斷(包括時鐘中斷),離開臨界區時開啟中斷。這使得CPU無法切換到其它程序。這種方案的缺點在於,將中斷遮蔽的程序可能不再將中斷開啟,導致CPU永遠無法切換程序;而且遮蔽的只是該程序對應的CPU的中斷,其它沒有被遮蔽中斷的CPU仍然可以訪問共享資源。在多核系統中,這種方法並不適用。

2、鎖變數
程序進入臨界區之前必須先持有鎖,然後將鎖佔有,其它程序得不到所而在臨界區外等待。但這種方案的缺陷在於,程序在判斷鎖可用到佔有鎖之間可能會被排程,另一個程序同樣發現鎖可用並進入臨界區。這會導致兩個程序同時進入臨界區。

3、嚴格輪換法
程序等待某個變數被置位後才能進入臨界區,如下圖所示:

程序a在turn變為0之前迴圈等待;程序b在turn變為1之前迴圈等待。這屬於忙等待,很顯然浪費了CPU時間。用於忙等待的鎖稱為自旋鎖。這種方案的問題在於,兩個程序必須按照嚴格的順序交替進入臨界區,這會降低速度較快的程序的執行效率。也就是違反了上述條件3.

4、Peterson演算法
該演算法非常簡單且有效,僅由兩個C函式構成:

關鍵的一點在於enter_region函式中的while迴圈,當兩個程序同時進入enter_region函式時,能夠確保先進入該函式的程序進入臨界區,而後進入的在while迴圈出等待。

5、TSL/XCHG指令
TSL指令的形式如下:
TSL RX, LOCK    # 將LOCK讀入暫存器RX並將1寫入LOCK所在記憶體,讀和寫是一個不可分割的原子操作
執行TSL的CPU將鎖住匯流排,這使得其它任何CPU都無法訪問共享記憶體,相當於遮蔽中斷的改進版。使用TSL指令的使用方法如下所示:

另一條指令XCHG原子性地交換兩個位置的內容,所以它可作為TSL指令的替代品控制程序進入臨界區,原理實際上和上圖是一樣的,如下圖所示。所有的Intel x86 CPU在底層同步中使用了XCHG指令。


休眠與喚醒
上述方案有一個共同的缺點就是程序在無法進入臨界區時,處於忙等待狀態,這浪費了CPU時間。要使程序在無法進入臨界區時阻塞,而不是等待,可以使用程序間通訊原語。例如:sleep、wakeup等。以下是另外一些程序間互斥、同步的方案。

1、訊號量
由大神Dijkstra提出,它包括down(P,表示嘗試)和up(V,表示增加)兩種操作,所以又稱PV操作:
down:檢查訊號量的值是否大於0,大於0則減1並繼續,等於0就休眠程序,整個操作不可分割。
up:對訊號量值增1,喚醒由於down操作而休眠的程序,使其繼續執行未完成的down操作,整個操作不可分割。
訊號量可用於程序間的互斥和同步。
互斥:在同一時刻只有一個程序能夠進行操作。例如互斥地進入臨界區。
同步:程序間的執行需要按照某種先後順序。例如生產者發現緩衝區滿時要停止;消費者發現緩衝區空時要停止。
使用訊號量解決生產者-消費者的例子:

其中,empty和full是用來實現同步的訊號量;mutex是用來實現互斥地訊號量。

2、互斥量
無計數能力,是訊號量的一個簡化版本。互斥量包含兩個狀態:解鎖(0)和加鎖(1)。執行緒加鎖和解鎖函式mutex_lock、mutex_unlock的實現如下:

這裡的mutex_lock和上面的enter_region的區別在於:呼叫mutex_lock的執行緒無法進入臨界區時會釋放CPU(thread_yield函式)執行另外的執行緒;而呼叫enter_region會不斷迴圈測試(忙等待),直到臨界區可用。

3、管程
使用訊號量和互斥量存在一個問題:死鎖。例如上面的訊號量部分程式碼中,如果將down(&empty)和down(&mutex)順序對調,那麼就有可能發生死鎖。原因在於當生產者先鎖住mutex,然後empty為0休眠後,消費者由於得不到mutex鎖而休眠,這樣兩個程序將永遠休眠下去。使用管程可解決這一問題。管程由過程、變數、資料結構等組成的一個模組,程序間必須互斥地訪問這個模組中的過程,如下圖所示。管程的重要特性是,在任一時刻管程中只能有一個活躍程序。

上圖有一個名為example的管程,包含一個整型變數i、一個條件變數c和兩個過程。管程為程序的互斥訪問提供了環境,接下來要解決的是同步問題。解決方法是使用條件變數:當管程中的過程發現自己無法繼續執行時(例如生產者發現緩衝區滿),會在某個條件變數身上執行wait操作阻塞自身並將其它程序調入管道;另一個程序(如消費者)對緩衝區進行消費後,可以呼叫signal向條件變數傳送訊號以喚醒因呼叫wait而阻塞的程序(如生產者),然後自身退出管程,被喚醒的程序進入管程。

4、訊息傳遞
通過兩條原語send和receive在程序間進行通訊,send為傳送訊息而receive為接收訊息(有可能發生阻塞),也就是讓訊息稱為共享資源的載體。使用訊息傳遞機制解決生產者-消費者問題的程式碼如下:

5、屏障
一種應用於程序組的同步機制。它規定,所有程序都完成了第n階段,才能進入第n+1階段。也就是說,當有程序完了第n階段而另一些程序沒有完成第n階段時,完成的那些程序是需要阻塞等待未完成程序的,如下圖所示。這可以在每個階段的末尾新增屏障來實現這一功能。

--------------------- 
作者:Nestler 
來源:CSDN 
原文:https://blog.csdn.net/nestler/article/details/37727689 
版權宣告:本文為博主原創文章,轉載請附上博文連結!