信號量
信號量的英文叫做 semaphore,是一個用於在進程間傳遞的特殊便量,通常定義成一個結構體,其中包含一個整形變量,以及一個隊列,如下:
struct semaphore {
int count;
Queue queue; // 存放進程
}
-
semaphore.count
信號量的值 (count) 與相應資源的使用情況有關。當count > 0
時,表示當前可用資源的數量,當count < 0
時,其絕對值就表示當前等待使用資源的進程數。這邊要注意,semaphore.count
只能由 PV 操作來改變! -
semaphore.queue
semaphore.queue
的作用在於,存放那些被阻塞的進程(等待被喚醒的進程)。就是說,假設當前沒有可用資源了(semaphore.count <= 0)
,那麼這時如果又有進程想要使用資源,這時該進程應該進入阻塞狀態,我們就將該進程加入到semaphore.count
中。
而當今天某些資源被釋放了(semaphore.count > 0)
,那這時我們就要喚醒最早開始等待的那個進程,也就是semaphore.count
的隊列開頭。因此這邊採用先進先出的隊列是比較合適的。
PV 操作
一般來說,S >= 0,S 表示可用資源數量。執行一次 P 操作意味著請求分配一個單位資源,因此 S–,當 S <= 0 表示已經沒有可用資源了,這時請求者就必須等待別的進程釋放該資源,它才能繼續運行,否則就進入阻塞狀態。
而執行一次 V 操作意味著釋放一個單位資源,因此 S++,而當執行完一次 V 操作後,如果此時 S < 0,就表示說當前還有 |S| 個正在等待的阻塞態進程,因此要喚醒一個進程,使之運行下去。
在往下看 PV 操作的實現之前,我們先假設,當前調用 PV 操作的進程為 p_proc_ready
,然後對一個進程而言,有兩種狀態(pv_state
),分別為阻塞態 PV_PROCESS_BLOCK
以及就緒態 PV_PROCESS_READY
。
並且,我們還要加上一個 schedule()
方法,目的是在執行完 P 操作後,因為當前進程進入了阻塞態,因此我們要找到下一個要執行的進程並把控制權交給它,簡單來說,schedule()
就是負責重新調度。
P 操作
P 操作意味請求分配一個資源,也稱為 wait() 操作,使 S–,若 S < 0,進程進入阻塞態,放入信號量的等待隊列。
P(semaphore S) {
S.count--;
if(S.count < 0) {
p_proc_ready->pv_state = PV_PROCESS_BLOCK;
S.queue.add(p_proc_ready);
schedule();
}
}
V 操作
V 操作意味釋放一個單位資源,也可以稱為 signal() 操作,使 S++&#