程序同步工具之 訊號量機制

2022-06-10 11:54:06 字數 4214 閱讀 6051

程序同步、程序互斥的兩種機制,這裡簡單總結是其中的訊號量機制(semaphores)

建議:不少概念涉及到程序同步的內容,所以檢視這個內容時可以結合或提前參考程序同步的內容,

訊號量機制是 荷蘭學者 dijkstra 提出的,這是一種卓有成效的程序同步工具。發展:整型訊號量->記錄型訊號量->and 型訊號量->訊號量集,依次講解下。

定義:把整型訊號量定義為乙個用於表示資源數目的整型量 s,它與一般整型 量不同,除初始化外,僅能通過兩個標準的原子操作(atomic operation) wait(s)和 signal(s)來訪問。

pv操作由p操作原語和v操作原語組成(原語是執行時不可中斷,pv操作即定義中的原子操作wait(s)和signal(s))。因此這個操作通常被叫做pv操作。

注:在荷蘭文中,通過叫passeren,釋放叫vrijgeven,pv操作因此得名。wait(s)即申請資源,signal(s)釋放資源。

描述:

wait(s) 

signal(s)

不足:當s<=0時,就要不斷檢測。陷入「忙等」狀態,不符合讓權等待。(在程序同步總結中有詳細說明)

在整型訊號量基礎上,增加了乙個程序鍊錶指標l,鏈結所有等待的程序。

資料結構定義描述如下:乙個整型變數value表示資源數目程序鍊錶指標l

typedef struct semaphore;

相應的,wait(s)和signal(s)操作過程就是:

當wait(s)申請資源時,s.value減1(為負數時的絕對值即等待程序的數目)。若s.value<0時表示資源耗盡了,程序使用block原句 自我阻塞,放棄處理機,插入到等待程序鍊錶中s.l。這就符合了讓權等待,避免了「忙等」。

當signal(s)釋放資源,s.value加1。若加 1 後仍是 s.value≤0,則表示在該鍊錶l中,仍有等待該資源的程序被阻塞,故還應 呼叫 wakeup 原語,將 s.l 鍊錶中的第乙個等待程序喚醒。

如果 s.value 的初值為 1,表示只允許乙個程序訪問臨界資源,此時的訊號量轉化為互斥訊號量,用於程序互斥。

void

wait(semaphore s)

}void

signal(semaphore s)

}

不足:同整型訊號量一樣,都是正對的是共享一種臨界資源。 若乙個程序需要兩個或更多資源後才可執行,就會出現死鎖的可能,共享資源越多,程序死鎖可能性越大。

比如:有兩個程序a、b。兩個臨界資源d、e,互斥訊號量(初值為1)分別是dmutex、emutex。

按下面執行次序,a獲得了d等待e,b獲得了e等待d,就處於了僵持狀態,無外界干預,a、b就陷入了死鎖狀態。共享資源越多,程序死鎖可能越大。

process a: wait(dmutex); 於是 dmutex=0 

process b: wait(emutex); 於是 emutex=0 

process a: wait(emutex); 於是 emutex=-1 a 阻塞

process b: wait(dmutex); 於是 dmutex=-1 b 阻塞

如上所述,整型訊號量和記錄型訊號量當共享多種臨界資源時都容易引起死鎖問題。and型訊號量能夠避免上述死鎖情況的出現。

and同步機制:要麼把程序在整個執行過程中所請求的資源全部分配到程序(程序使用完成後一起釋放),要麼乙個也不分配。

描述:wait():申請資源s1-sn,當碰到si不滿足後,則執行else裡,將程序加入到si關聯的等待佇列中 而程序指標移向wait()開始。wait()是原語,不可中斷。

wait(s1,s2,...,sn)  

else

}

signal():釋放資源s1-sn,將s1-sn關聯的等待佇列清空 並調入就緒佇列。

signal(s1,s2,...,sn) 

}

不足:整型訊號量、記錄型訊號量侷限在只共享一種臨界資源。and型訊號量侷限在單種(一種)臨界資源為1,若單種資源為n(n>=1)時,and型訊號量的wait()和signal()就需操作n次,這是很低效的。

但很多情況是乙個程序可能申請多種臨界資源且某種臨界資源數目大於1的。

如上所述。當需要單種資源為n(n>=1),and型操作 wait()和signal()需要操作n次,低效。

除低效問題,還考慮情景:當某種資源數低於某一下限時變不在分配,因此每次都需檢測該資源數是否大於下限值。

從而衍生出了訊號量集:

操作可描述如下,其中 s 為訊號量,d 為需求值,而 t 為下限值。

wait():申請s1-sn, si需要di個,而資源si下限為ti。當s1-sn中,si不滿足下限值ti後,就不能分配了。進入else,程序加入到等待佇列,指標移向wait()開始位置。

wait(s1,t1,d1,…,sn,tn,dn)  

else

}

signal():釋放資源s1-sn,si釋放di個,s1-sn關聯的等待佇列清空 並調入就緒佇列。

signal(s1,d1,…,sn,dn) 

}

「訊號量集」的幾種特殊情況:

(1) swait(s,d,d)。此時在訊號量集中只有乙個訊號量 s,每次申請 d 個資 源,當現有資源數少於d 時,不予分配。

(2) swait(s,1,1)。此時的訊號量集已蛻化為一般的記錄型訊號量(s>1 時)或互斥訊號 量(s=1 時)。 

(3) swait(s,1,0)。這是一種很特殊且很有用的訊號量操作。當 s>=1 時,允許多個程序進入某特定區;當 s 變為 0 後,將阻止任何程序進入特定區。換言之,它相當於乙個可

控開關。

為使多個程序能互斥地訪問某臨界資源,只須為該資源設定一互斥訊號量 mutex,並設其初始值為 1,然後將各程序訪問該資源的臨界區 置於 wait(mutex)和 signal(mutex)操作之間即可。

var mutex: semaphore:=1;

process 1: begin 

repeat

wait(mutex);

critical section

signal(mutex);

remainder seetion

until

false

;end

process 2: begin

repeat

wait(mutex);

critical section

signal(mutex);

remainder section

until

false

;end

在利用訊號量機制實現程序互斥時應注意,wait(mutex)和 signal(mutex)必須成對地出現。 缺少 wait(mutex)將會導致系統混亂,不能保證對臨界資源的互斥訪問;而缺少 signal(mutex)將會使臨界資源永遠不被釋放,從而使因等待該資源而阻塞的程序不能被喚醒。

設有兩個併發執行的程序 p1 和 p2。p1 中有語句 s1;p2 中有語句 s2。

我們希望在 s1 執行後再執行 s2。為實現這種前趨關係: s1->s2。

我們只須使程序 p1 和 p2 共享乙個公用訊號量 s,並賦予其初值為 0,將 signal(s)操作放在語句 s1 後面;而在 s2 語句前面插入 wait(s)操作,

在程序 p1 中

s1;

signal(s);

在程序 p2 中

wait(s);

s2;

由於 s 被初始化為 0,這樣,若 p2 先執行必定阻塞,只有在程序 p1 執行完 s1;signal(s);操作後使 s 增為 1 時,p2 程序方能執行語句 s2 成功。

這是最基礎的實現,在此基礎上可以實現更多程序間更複雜的前後驅關係,需要多個公共訊號量協同操作。

程序同步 訊號量機制

由dijkstra提出,目前已廣泛應用於單處理機和多處理機系統以及計算機網路中。一 整形訊號量 1.s 乙個用於表示資源數目的整型量 2.與一般整型量不同,除初始化外,僅能通過兩個標準的原子操作 wait s 和signal s 長期以來一直被稱為p v操作 3.wait操作偽碼描述 wait s ...

程序同步與訊號量

對於多個程序訪問共享資料,需要程序進行同步合作完成操作。我們可以使用訊號量來描述共享資料。struct semaphore p semaphore s v semaphore s 這樣的話當我們訪問共享資料時,我們可以先呼叫p操作,訪問結束後呼叫v操作,這樣就可以當成程序同步的目的。使用訊號量的問題...

程序同步與訊號量

二.訊號量臨界區保護 三.訊號量的 實現 訊號量是用來記錄可用資源或等待執行緒數目的一種特殊的整形變數。通過對訊號量的修改,使得各個程序得以有序推進,完成程序同步。訊號量的 定義 struct semaphore兩種基本操作 當程序申請消費資源時執行p函式。首先將資源數目value減一,然後判斷va...