看完了進程同步與互斥機制,我終於徹底理解了 PV 操作


🎓 盡人事,聽天命。博主東南大學碩士在讀,熱愛健身和籃球,樂於分享技術相關的所見所得,關注公眾號 @ 飛天小牛肉,第一時間獲取文章更新,成長的路上我們一起進步

🎁 本文已收錄於 CS-Wiki(Gitee 官方推薦項目,現已累計 1.4k+ star),致力打造完善的后端知識體系,在技術的路上少走彎路,歡迎各位小伙伴前來交流學習

 

全文脈絡思維導圖如下:

1. 什么是進程同步

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

那么,進程的異步性會帶來什么問題呢?舉個例子,如果有 A、B 兩個進程分別負責讀和寫數據的操作,這兩個線程是相互合作、相互依賴的。那么寫數據應該發生在讀數據之前。而實際上,由於異步性的存在,可能會發生先讀后寫的情況,而此時由於緩沖區還沒有被寫入數據,讀進程 A 沒有數據可讀,因此讀進程 A 被阻塞。

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

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

注意不要把進程同步和進程調度搞混了:

  • 進程調度是為了最大程度的利用 CPU 資源,選用合適的算法調度就緒隊列中的進程。

  • 進程同步是為了協調一些進程以完成某個任務,比如讀和寫,你肯定先寫后讀,不能先讀后寫吧,這就是進程同步做的事情了,指定這些進程的先后執行次序使得某個任務能夠順利完成。

2. 什么是進程互斥

同樣的,也是因為進程的並發性,並發執行的線程不可避免地需要共享一些系統資源,比如內存、打印機、攝像頭等。舉個例子:我們去學校打印店打印論文,你按下了 WPS 的 “打印” 選項,於是打印機開始工作。 你的論文打印到一半時,另一位同學按下了 Word 的 “打印” 按鈕,開始打印他自己的論文。想象一下如果兩個進程可以隨意的、並發的共享打印機資源,會發生什么情況?

顯然,兩個進程並發運行,導致打印機設備交替的收到 WPS 和 Word 兩個進程發來的打印請求,結果兩篇論文的內容混雜在一起了。

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

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

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

  • 進程同步:進程 A 應在進程 B 之前執行

  • 進程互斥:進程 A 和進程 B 不能在同一時刻執行

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

3. 常見的進程同步與互斥機制

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

  • 信號量與 PV 操作

  • 管程

① 信號量與 PV 操作

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

1965年,荷蘭學者 Dijkstra 提出了一種卓有成效的實現進程同步和互斥的方法 — 信號量機制(Semaphore)。信號量其實就是一個變量 ,我們可以用一個信號量來表示系統中某種資源的數量,比如:系統中只有一台打印機,就可以設置一個初值為 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 操作具體的定義如下:

實現進程互斥

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

  • 定義一個互斥信號量,並初始化為 1

  • 把對於臨界資源的訪問置於 P 操作和 V 操作之間

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

實現進程同步

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

舉個例子,以下兩個進程 P1、P2 並發執行,由於存在異步性,因此二者交替推進的次序是不確定的。假設 P2 的 “代碼4” 要基於 P1 的 “代碼1” 和 “代碼2” 的運行結果才能執行,那么我們就必須保證 “代碼4” 一定是在 “代碼2” 之后才會執行。

如果 P2 的 “代碼4” 要基於 P1 的 “代碼1” 和 “代碼2” 的運行結果才能執行,那么我們就必須保證 “代碼4” 一定是在 “代碼2” 之后才會執行。

使用信號量和 PV 操作實現進程的同步也非常方便,三步走:

  • 定義一個同步信號量,並初始化為當前可用資源的數量

  • 在優先級較的操作的面執行 V 操作,釋放資源

  • 在優先級較的操作的面執行 P 操作,申請占用資源

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

生產者和消費者問題

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

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

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

  • 同步關系 1:只有緩沖區沒滿時(優先級高),生產者才能把產品放入緩沖區(優先級低),否則必須等待

  • 同步關系 2:只有緩沖區不空時(優先級高),消費者才能從中取出產品(優先級低),否則必須等待

  • 互斥關系:緩沖區是臨界資源,各進程必須互斥地訪問。

既然這個題目有兩個同步關系和一個互斥關系,那么我們就需要兩個同步信號量和一個互斥信號量:

  • empty:同步信號量(對應同步關系 1),表示生產者還能生產多少,即還能放入緩沖區多少產品,該數量小於等於 0,則生產者不能進行生產。 初始化為 n。

  • full:同步信號量(對應同步關系 2),表示消費者還能從緩沖區取出多少,即當前緩沖區已有產品的數量,該數量小於等於 0,則消費者不能進行讀取。初始化為 0。

  • mutex:互斥信號量,實現對緩沖區的互斥訪問。初始化為 1。

代碼如下,注意各個 PV 操作的配對:

② 管程

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

其實使用管程是能夠實現信號量的,並且也能用信號量實現管程。但是管程封裝的比較好,相比起信號量來需要我們編寫的代碼更少,更加易用,這也就是 Java 采用管程機制的原因,synchronized 關鍵字及 wait()notify()notifyAll() 這三個方法都是管程的組成部分。把管程翻譯為 Java 領域的語言,就是管理類的成員變量和成員方法,讓這個類是線程安全的。再詳細的部分就不再深究了,溜了溜了。

🎉 關注公眾號 | 飛天小牛肉,即時獲取更新

  • 博主東南大學碩士在讀,利用課余時間運營一個公眾號『 飛天小牛肉 』,2020/12/29 日開通,專注分享計算機基礎(數據結構 + 算法 + 計算機網絡 + 數據庫 + 操作系統 + Linux)、Java 基礎和面試指南的相關原創技術好文。本公眾號的目的就是讓大家可以快速掌握重點知識,有的放矢。希望大家多多支持哦,和小牛肉一起成長 😃

  • 並推薦個人維護的開源教程類項目: CS-Wiki(Gitee 推薦項目,現已累計 1.4k+ star), 致力打造完善的后端知識體系,在技術的路上少走彎路,歡迎各位小伙伴前來交流學習 ~ 😊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM