🧠 背景:為什么會有 PV?
類比:內存(生產者) 和 CPU(消費者)
-
內存 / IO / 磁盤 / 網絡下載 → 不斷“生產數據”
-
例如:讀取文件、下載視頻、從數據庫加載信息
-
-
CPU → 負責“消費數據”
-
例如:處理數據、解碼、渲染畫面、計算結果
-
👉 由于生產和消費速度可能存在差異(如內存大、CPU處理慢),需要一個緩沖區(如緩存、隊列)進行協調。
🔧 三個基本模板
1. 信號量
-
定義:表示當前可用資源的個數。
2. 同步:控制先后順序
-
核心:信號量初始設為 0;
V
操作釋放信號量,進程 B 才能有資源繼續執行。 -
問題:如果信號量初始值為 0,進程 A 和進程 B 都會被阻塞嗎?
-
回答:是的,這樣可以保證進程 A 和 B 的先后順序。
-
3. 互斥:保證一個進程對資源的訪問
-
核心:使用
P
和V
操作夾住臨界區(臨界資源存放點)。
進程A; mutex=1
P(互斥信號量); mutex--; 0;
臨界區;
V(互斥信號量) mutex++; 1;進程B;
P(互斥信號量);
臨界區;
V(互斥信號量)
🏭 生產者-消費者模型
? full
是什么意思?
-
定義:在生產者-消費者模型中,
full
是一個信號量,用來表示當前緩沖區中“已經存了多少個產品”,也可以理解為“可供消費者消費的數據數量”。
? mutex
是什么?
-
定義:
mutex
是 mutual exclusion(互斥)的縮寫,表示一次只允許一個線程/進程訪問共享資源。用于保護臨界區。
🔄 同步與互斥關系
同步關系
-
生產者先生產出一個產品 →
V(full)
,消費者才能消費一個產品 →P(full)
。 -
消費者從緩沖區取來產品 →
V(empty)
,釋放一個空位,生產者才能繼續生產 →P(empty)
。
互斥關系
-
使用
P(mutex)
加鎖緩沖區,V(mutex)
釋放緩沖區,確保緩沖區的互斥訪問。
? 常見問題解答
問題:緩沖區初始為空,empty = n
(如 10 個空位),為什么還需要等待消費者“消費”后產生空位?不是一開始就很多空位了嗎?
-
答案:
-
? 一開始當然不需要等消費者,可以直接放數據進去!
-
🛑 但如果生產得太快,把緩沖區塞滿了(
empty == 0
),就必須等消費者先消費一個產品(釋放一個空位)才能繼續生產。
-
🧑?💻 生產者代碼解釋
-
生產:在自己線程內處理好數據(不影響別人)。
-
P(empty)
:檢查是否有空位(資源控制)。 -
P(mutex)
:進入緩沖區前加鎖(互斥控制)。 -
放入緩沖區。
-
V(mutex)
:解鎖。 -
V(full)
:通知消費者“有東西可以用了”。
👩?💻 消費者代碼解釋
-
P(full)
:等待是否有產品可取。 -
P(mutex)
:加鎖,準備訪問緩沖區。 -
取產品:真正的“消費”動作。
-
V(mutex)
:解鎖。 -
V(empty)
:通知生產者釋放了一個空位。 -
消費:轉到自己的線程輸出數據。
讀者-寫者(互斥)
📖 讀者-寫者問題(互斥)
問題:為什么 mutex
需要夾住 count
,不是允許多個讀者同時讀嗎?
-
回答:是的,多個讀者可以同時讀,但是
count
是一個“全局變量”,多個線程同時修改它會出問題,所以必須用mutex
來保護它!
🔄 同步與互斥關系
同步關系
-
讀者讀完后,解鎖并將
count--
。當count
為 0 時,表示最后一個讀者離開,此時寫者可以開始寫。 -
簡單來說:第一個讀者來關寫者的門,最后一個讀者來開寫者的門。
互斥關系:
互斥關系
-
count
的初始值為 0,表示沒有讀者在讀。 -
如果有寫者正在寫,
rw = 0
,讀者會被阻塞,等待寫者寫完。 -
如果沒有寫者寫,
rw = 1
,第一個讀者執行P(rw)
,然后繼續執行。
? 常見問題解答
問題:如果第一個讀者還沒執行到 V(mutex)
,第二個讀者就進來了,會怎么樣?第二個還能繼續嗎?
-
答案:
-
? 第二個讀者進不來,它會被阻塞在
P(mutex)
這里,直到第一個讀者執行V(mutex)
,它才能繼續往下執行。 -
? 雖然讀者可以“同時讀”,但它們更新計數器
count
時一定是串行的、有序的、安全的!
-
相對寫優先(有限)
設置P(w)V(w):
1:當讀進程先來時候,執行P(W),W=0,寫進程堵塞,只有當讀進程釋放了,寫進程才能進來。
2:當寫進程先來時候,執行P(W),W=0,讀進程堵塞,只有當寫進程釋放了,讀進程才能進來。
哲學家用餐(都會有幾率導致死鎖)
限制n-1哲學家就餐
使用信號量(semaphore count=4)限制同時就餐的哲學家數量為4個,理論上想避免所有5個哲學家同時拿筷子。但如果4個哲學家分別拿了一根筷子(例如,0號拿0筷子,1號拿1筷子,依此類推),第5個哲學家無法進入就餐,而已進入的4個哲學家仍在等待另一根筷子,依然會死鎖。
僅當左右筷子可用時候,才會吃飯。
使用mutex緊緊夾住拿筷子的動作
每個哲學家都先試圖拿左筷子(P(chopsticks[i])),再拿右筷子(P(chopsticks[(i+1)%5]))。如果所有哲學家同時拿左筷子,就會形成循環等待(每個人都拿著一根筷子,等待另一根),導致死鎖。
奇數號先拿左筷子。偶數號拿右筷子
哲學家編號為:1 ~ 5,筷子編號也為 1 ~ 5
每位哲學家要吃飯,必須拿 左手邊和右手邊的筷子:
-
哲學家 i 的左手筷子編號:i
-
哲學家 i 的右手筷子編號: (i % 5) + 1
這里試圖通過讓一個哲學家(if(i%2==0))先拿左筷子,其他人先拿右筷子來打破對稱性。但如果所有哲學家同時進入循環,依然可能出現循環等待。例如,編號為偶數的哲學家拿左筷子,編號為奇數的拿右筷子,最終還是會形成死鎖。
ChatGPT鏈接:https://chatgpt.com/share/680274c9-faec-800c-8a90-253e36512386