信號量 PV 操做

信號量的類型定義

通常來講,信號量(semaphore)\(S\),表示資源數量減去需求數量。信號量的值僅能由 PV 操做來改變。spa

執行一次 P 操做意味着請求一個單位資源,所以 \(S\) 的值減 1;當 \(S < 0\) 時,需求數大於資源數,即已經沒有可用資源,請求者必須等待。線程

執行一個 V 操做意味着釋放一個單位資源,所以 \(S\) 的值加 1;若 \(S \ge 0\),此時資源數目能知足需求,因此能夠喚醒一個在等待的請求者,讓它獲取資源。code

\(S < 0\)\(|S|\) 即沒有獲得資源的請求者數目,也就是阻塞的線程數。隊列

用互斥量和條件變量能夠模擬信號量的行爲:資源

use std::sync::Condvar;
use std::sync::Mutex;

pub struct Semaphore {
    sem: Mutex<i32>,
    con: Condvar,
}

impl Semaphore {
    pub fn new(sem: i32) -> Self {
        Self {
            sem: Mutex::new(sem),
            con: Condvar::new(),
        }
    }

    pub fn p(&self) {
        let mut sem = self.sem.lock().unwrap();

        *sem -= 1;
        if *sem < 0 {
            let _ = self.con.wait(sem).unwrap();
        }
    }

    pub fn v(&self) {
        let mut sem = self.sem.lock().unwrap();

        *sem += 1;
        if *sem <= 0 {
            self.con.notify_one();
        }
    }
}

互斥

當信號量的初始值取 1,任何第二個請求資源者會陷入飢餓。從而同一時刻只能有一個線程訪問某個資源。同步

初始化一個信號量 mutexSemaphore::new(1),在使用臨界資源以前調用 mutex.p(),使用完資源以後調用 mutex.v()。即實現了資源的互斥訪問。it

同步

設置起始資源爲大於 1 的正數,則 PV 操做維護資源同步。class

舉例說明,要實現有 3 個緩衝區的、MPMS 的隊列。抽象出兩種資源:緩衝區空間(room)和隊列中的數據(data)。隊列爲空的狀況下,有 3 個 room 資源,沒有 data 資源。dva

let room = Semaphore::new(3);
let data = Semaphore::new(0);
let queue = Queue::empty();

要往隊列裏添加元素,則須要一個 room 資源,操做完以後產生一個 data 資源。變量

room.p();
queue.push(x);
data.v();

要從隊列頭取出元素,則須要一個 data 資源,操做完以後產生一個 room 資源。

data.p();
let x = queue.pop();
room.v();

(完)

相關文章
相關標籤/搜索