詳解程序同步與互斥機制

2022-09-25 01:18:11 字數 3120 閱讀 4125

目錄

在多道批處理系統中,多個程序是可以併發執行的,但由於系統的資源有限,程序的執行不是一貫到底的, 而是走走停停,以不可預知的速度向前推進,這就是程序的非同步性。

那麼,程序的非同步性會帶來什麼問題呢?舉個例子,如果有 a、b 兩個程序分別負責讀和寫資料的操作,這兩個執行緒是相互合作、相互依賴的。那麼寫資料應該發生在讀數程式設計客棧據之前。而實際上,由於非同步性的存在,可能會發生先讀後寫的情況,而此時由於緩衝區還沒有被寫入資料,讀程序 a 沒有資料可讀,因此讀程序 a 被阻塞。

程序同步(synchronization)就是用來解決這個問題的。從上面的例子我們能看出,乙個程序的執行可能影響到另乙個程序的執行,所謂程序同步就是指協調這些完成某個共同任務的併發執行緒,在某些位置上指定執行緒的先後執行次序、傳遞訊號或訊息。

再舉個生活中的程序同步的例子,你想要喝熱水,於是你打了一壺水開始燒,在這壺水燒開之前,你只能一直等著,水燒開之後水壺自然會發生響聲提醒你來喝水,於是你就可以喝水了。就是說水燒開這個事情必須發生在你喝水之前。

注意不要把程序同步和程序排程搞混了:

同樣的,也是因為程序的併發性,併發執行的執行緒不可避免地需要共享一些系統資源,比如記憶體、印表機、攝像頭等。舉個例子:我們去學校列印店列印**,你按下了 wps 的 「列印」 選項,於是印表機開始工作。 你的**列印到一半時,另一位同學按下了 word 的 「列印」 按鈕,開始列印他自己的**。想象一下如果兩個程序可以隨意的、併發的共享印表機資源,會發生什麼情況?

顯然,兩個程序併發執行,導致印表機裝置交替的收到 wps 和 word 兩個程序發來的列印請求,結果兩篇**的內容混雜在一起了。

程序互斥(mutual exclusion)就是用來解決這個問題的。當某個程序 a 在訪問印表機時,如果另乙個程序 b 也想要訪問印表機,它就必須等待,直到 a 程序訪問結束並釋放印表機資源後,b 程序才能去訪問。

實際上,像上述的印表機這種在乙個時間段內只允許乙個程序使用的資源(這也就是互斥的意思),我們將其稱為臨界資源,對臨界資源進行訪問的那段**稱為臨界區。

通俗的對比一下程序互斥和程序同步:

從上不難看出,程序互斥是一種特殊的程序同步,即逐次使用臨界資源,也是對程序使用資源的先後執行次序的一種協調。

常見的程序同步與互斥機制有兩種:

① 訊號量與 pv 操作

包交包會!看完下面這段解釋你絕對能夠明白 pv 操作是啥。

2023年,荷蘭學者 dijkstra 提出了一種卓有成效的實現程序同步和互斥的方法 — 訊號量機制(semaphore)。訊號量其實就是乙個變數 ,我們可以用乙個訊號量來表示系統中某種資源的數量,比如:系統中只有一台印表機,就可以設定乙個初值為www.cppcns.com 1 的訊號量。

使用者程序可以通過使用作業系統提供的一對原語來對訊號量進行操作,從而很方便的實現程序互斥或同步。這一對原語就是 pv 操作:

1)p 操作:將訊號量值減 1,表示申請占用乙個資源。如果結果小於 0,表示已經沒有可用資源,則執行 p 操作的程序被阻塞。如果結果大於等於 0,表示現有的資源足夠你使用,則執行 p 操作的程序繼續執行。

可以這麼理解,當訊號量的值為 2 的時候,表示有 2 個資源可以使用,當訊號量的值為 -2 的時候,表示有兩個程序正在等待使用這個資源。不看這句話真的無法理解 v 操作,看完頓時如夢初醒。

2)v 操作:將訊號量值加 1,表示釋放乙個資源,即使用完資源後歸還資源。若加完後訊號量的值小於等於 0,表示有某些程序正在等待該資源,由於我們已經釋放出乙個資源了,因此需要喚醒乙個等待使用該資源(就緒態)的程序,使之執行下去。

我覺得已經講的足夠通俗了,不過對於 v 操作大家可能仍然有困惑,下面再來看兩個關於 v 操作的問答:

問:訊號量的值 大於 0 表示有臨界資源可供使用,這個時候為什麼不需要喚醒程序?

答:所謂喚醒程序是從就緒佇列(阻塞佇列)中喚醒程序,而訊號量的值大於 0 表示有臨界資源可供使用,也就是說這個時候沒有程序被阻塞在這個資源上,所以不需要喚醒,正常執行即可。

問:訊號量的值 等於 0 的時候表示沒有臨界資源可供使用,為什麼還要喚醒程序?

答:v 操作是先執行訊號量值加 1 的,也就是說,把訊號量的值加 1 後才變成了 0,在此之前,訊號量的值是 -1,即有乙個程序正在等待這個臨界資源,我們需要喚醒它。

訊號量和 pv 操作具體的定義如下:

實現程序互斥

兩步走即可實現程序的互斥:

p 操作和 v 操作必須成對出現。缺少 p 操作就不能保證對臨界資源的互斥訪問,缺少 v 操作就會導致臨界資源永遠得不到釋放、處於等待態的程序永遠得不到喚醒。

實現程序同步

回顧一下程序同步,就是要各併發程序按要求有序地執行。

舉個例子,以下兩個程序 p1、p2 併發執行,由於存在非同步性,因此二者交替推進的次序是不確定的。假設 p2 的 「**4」 要基於 p1 的 「**1」 和 「**2」 的執行結果才能執行,那麼我們就必須保證 「**4」 一定是在 「**2」 之後才會執行。

如果 p2 的 「**4」 要基於 p1 的 「**1」 和 「**2」 的執行結果才能執行,那麼我們就必須保證 「**4」 一定是在 「**2」 之後才會執行。

使用訊號量和 pv 操作實現程序的同步也非常方便,三步走:

配合下面這張圖直觀理解下:

生產者和消費者問題

下面我們利用訊號量和 pv 操作來解決經典的程序同步和互斥問題:生產者和消費者問題。

【問題描述】:系統中有一組生產者程序和一組消費者程序,生產者程序每次生產乙個產品放入緩衝區,消費者程序每次從緩衝區中取出乙個產品並使用。任何時刻,只能有乙個生產者或消費者可以訪問緩衝區。

由題可知,生產者、消費者共享乙個初始為空、大小為 n 的緩衝區,我們從題目中提煉出同步與互斥關係:

既然這個題目有兩個同步關係和乙個互斥關係,那麼我們就需要兩個同步訊號量和乙個互斥訊號量:

**如下,注意各個 pv 操作的配對:

② 管程

管程有乙個重要特性:在乙個時刻只能有乙個程序使用管程。程序在無法繼續執行的時候不能一直占用管程,否則其它程序將永遠不能使用管程。也就是說管程天生支援程序互斥。

其實使用管程是能夠實現訊號量的,並且也能用訊號量實現管程。但是管程封裝的比較好,相比起訊號量來需要我們編寫的**更少,更加易用,這也就是 j**a 採用管程機制的原因,synchronized關鍵字及wait()、notify()、notifyall()這三個方法都是管程的組成部分。把管程翻譯為 j**a 領域的語言,就是管理類的成員變數和成員方法,讓這個類是執行緒安全的。

程序同步與互斥

程序同步與互斥 首先,我們看乙個例子 程序p1 p2公用乙個變數count,初始值為0 p1 p2兩個程序的執行順序是隨機的,p1 p2可能順序執行或交錯執行。由圖可見,不同的執行順序,count值會不同,這是不允許的。在多道程式系統中,由於資源共享或程序合作,使程序間形成間接相互制約和直接相互制約...

程序同步與互斥

為什麼要引入程序同步的概念?多道程式環境下的程序併發執行,它們相互之間存在著不同的制約關係,為了理解和協調這種制約的關係,引入了程序同步的概念。臨界資源是一次只能為乙個程序使用的資源。由於臨界資源的特性,就決定了 對它的訪問必須是互斥的。在每個程序中,訪問臨界資源的那段 稱為臨界區。為了保證臨界資源...

程序 同步與互斥基礎

臨界區 具體一點,在程式中,臨界區就是一段 區域,這段 區在任何時間點至多只有乙個程序在執行它的 打個比方 有個大公尺庫所,裡面裝了若干袋的大公尺,前台有個記錄冊記錄了當前庫所的庫存。當乙個員工運來大公尺時,他首先參看記錄冊中記錄了多少袋大公尺,然後將自己送來的大公尺放入倉庫,最後將自己新加入的大公...