訊號量和管程都是作業系統用於同步提供的兩種方法,我們將結合生產者與消費者模型對此進行學習。
為了提高系統的併發性,我們引入了多程序,多執行緒,但是這樣子帶來了資源競爭,也就是多個程式同時訪問乙個共享資源而引發的一系列問題,因此我們需要協調多執行緒對與共享資源的訪問,在任意時刻保證只能有乙個執行緒執行臨界區**。為了實現同步,我們可以利用底層硬體支援,也可以利用高層次的程式設計抽象,訊號量和管程屬於後者,是高層次的一種抽象,如下圖:
訊號量(semaphore)是一種抽象資料型別,它是由乙個(sem)整型變數(用於表示資源數目)和兩個原子操作p,v組成。
這兩個操作分別是:
p操作:在申請資源時候使用,將sem減1,如果sem小於0,就進入等待,否則直接使用資源即可,注意p操作有可能因為沒有資源進入阻塞
v操作:在釋放資源時候使用,將sem加1,如果sem依舊小於等於0,說明之前有程序在等待使用這個資源,因此需要喚醒乙個等待程序
由定義,我們給出訊號量的偽**實現:
class
semaphore
}q()}}
訊號量可分為兩種:
二進位制訊號量:資源數目0或者1
資源訊號量:資源數目為任意非負值
這兩者等價,基於乙個可以實現另乙個
訊號量一般用於兩種情況:
互斥訪問:臨界區的互斥訪問控制
我們看乙個例子,假設有乙個共享資源,程序p0,p1對它進行操作,我們希望p0,p1都是互斥訪問這個共享資源,那麼我們該如何用訊號量實現臨界區的互斥訪問?我們為此資源設定乙個訊號量,初值為1,mutx = new semaphore(1)
mutex->p();
critical section;//臨界區操作
mutex->v();
由於p0,p1訪問順序的不確定性,我們不妨讓p0先訪問(p1同理),p0執行mutex->p(),將資源mutex數目由1減為0(這一步是原子操作不可打斷)
此時,如果p1不行進行訪問,那麼p0會順利執行臨界區操作,如果p1進行訪問,那麼由於p0已經執行了對應的p操作讓sem=0,p1自己在執行p操作過程中,sem減1等於-1,那麼p1程序會阻塞自己,進入等待佇列。
直到p0訪問完臨界區,執行v操作,將mutex加1等於0,去喚醒p1程序,p1才會去訪問共享資源。
通過這樣的一種機制,完成了對於臨界區的互斥訪問。
條件同步:執行緒之間的時間等待
同樣的,我們舉例說明,有兩個程序a,b,他們會執行各自的指令
其中,執行緒a必須等執行緒b中x指令執行完才可以執行n指令,比如說x是接受資料,n是處理資料這樣的操作等。。。
為了實現這樣的同步機制,我們條件設定乙個訊號量,其初值為0
由於a,b的執行次序不定,我們分類討論。
b先執行:b執行到v操作時候,將condition從0加為1,此時如果切換到a執行,那麼a執行到p操作,發現condition-1為0,可以繼續執行n指令
a先執行:a執行到p操作時候,將condition從0減為-1,由於condition<0,則a會阻塞自己,接下來b執行到v操作,將condition從-1加到0,此時b知道有程序在等待資源,因此它去喚醒a,a因此執行了n指令
通過這樣的機制完成同步等待。
在上述中,將mutex訊號量用於完成互斥訪問,full,empty則用於完成問題分析中兩個條件同步,因此我們將乙個實際問題轉化為訊號量可以解決的問題。
如上圖,我們在類中定義了三個訊號量用於完成互斥,同步操作,初始時候,mutex表示資源為1,full表示當前滿緩衝區的個數為0,empty表示當前buffer都為空,(我們設定緩衝取的大小為n,因此full+empty == n)
首先必須保證互斥操作,也就是任意時刻只有乙個執行緒能操作緩衝區,要麼是生產者,要麼是消費者,因此我們在deposit(生產者),remove(消費者)中分別進行了pv操作。(具體過程和上面互斥訪問一致,不清楚可以往前翻看)
下面我們要來處理緩衝區滿或者空時,條件同步是如何實現的?
對於生產者,如果緩衝區滿,則必須阻塞自己,只有等消費者消費了,緩衝區還有空緩衝區才能夠繼續生產,因此,我們需要同時改寫deposit(c)和remove(c)的**:
deposit(c)
remove(c)
同理對於消費者,如果緩衝區為空,則必須阻塞自己,只有等生產者生產了,緩衝區還有東西才能夠繼續消費,因此,我們也需要同時改寫deposit(c)和remove(c)的**:
生產者 消費者模型之訊號量
訊號量 1 定義訊號量 sem t semaphore 定義乙個名為semaphore的訊號量 2 初始化訊號量 int sem init sem t sem,int pshared,unsigned int value 引數 sem t sem 要初始化的訊號量 int pshared pshar...
POSIX訊號量 生產者消費者模型
今天我們來寫乙個基於固定大小的環形佇列的生產者消費者模型。首先來畫圖說明一下 這是乙個環形佇列的生產者消費者模型。生產者用p表示,消費者用c表示。這個環形佇列的每一段空間我們用semblank表示,放入的內容我們用semdata表示。生產者首先要申請乙個semblank,然後放入semdata。消費...
Linux訊號量機制(生產者消費者)
該程式為linux訊號量機制實現程式,主要模擬了一般的生產者 消費者問題。生產者 消費者問題是乙個經典的程序同步問題,該問題最早由dijkstra提出,用以演示他提出的訊號量機制。在同乙個程序位址空間內執行的兩個執行緒。生產者執行緒生產物品,然後將物品放置在乙個空緩衝區中供消費者執行緒消費。消費者執...