作業系統筆記 程序同步(3)

2022-09-07 09:51:11 字數 4258 閱讀 3454

讀者寫者問題

哲學家就餐問題

小結描述

這是乙個多程序併發協作的問題(也可以是多執行緒),在這裡我們涉及到了兩類程序,一類是生產者程序,一類是消費者程序,生產者用於生產資料,消費者用於處理生產者生產的資料,所有消費者處理的資料必須由生產者生產得到。

為了解耦這兩類程序之間的關係,我們引入乙個資料緩衝池,這個緩衝池用於儲存資料。生產者將資料產生後投入這個緩衝池中,消費者直接由這個緩衝池中取出資料,這樣就不必考慮這兩個程序之間的相關依賴,即(解耦)。兩個程序只需對緩衝區進行操作即可。生產者只有在緩衝區沒有填滿時才能繼續生產,否則就會被阻塞,消費者只有在緩衝區中還有資料時才能對裡面的資料進行操作,如果緩衝區為空,那麼將沒有資料供消費者處理,生產者程序會被阻塞。而且兩個程序對緩衝區的訪問可能是阻塞的(即緩衝池是臨界資源)。

圖中p是生產者,c是消費者。

先整理一下語義:緩衝不為空時消費者可以去資料處理,緩衝沒有滿時,生產者可以生產資料存入緩衝中。對緩衝的操作是阻塞訪問。

int full=0;

//表示消費者可用的空間

int empty=n;

//表示生產者可用的空間

//初始狀態緩衝區全為空

int visit=1;

//對緩衝的訪問

//---------------上面全是訊號量----------------

resuouse buf[n]

;//緩衝的空間

int in=0;

//生產者對buf的訪問指標

int out=0;

//消費者對buf的訪問指標

//初始狀態都為0

接下來就是對於原語的乙個偽**描述

wait

(int

&s)}

signal

(int

&s)}

由於這裡的訊號量所描述的都是大於零時可以訪問,所以其原語對應操作相同。

接下來就是生產者與消費者的偽**描述

producer()

}consumer()

}

分情況討論

接下來我們來對不同情況進行分別討論。

主要是一下幾種:

單生產者單消費者、多緩衝時(緩衝區空間大於1)

多生產者多消費者、單緩衝時(緩衝區空間為1)

單生產者單消費者、單緩衝時(緩衝區空間為1)

當緩衝區無限大(緩衝區空間為無窮大)

上面的實現是乙個標準的實現,可以適用於所有的情況。

但是對於單緩衝的情況,我們可以將visit的訊號量去除,因為只有乙個緩衝空間,要麼full為1,要麼empty為1,所以不需要再使用乙個visit訊號量。

對於空間足夠大的緩衝區時,生產者不需要檢查是否有空閒空間,所以不需要wait(empty),同時消費者處理完後也不用釋放empty的空間,或者說不需要記錄empty的訊號量,所以可以刪除對於empty的維護。

訊號量的釋放順序

wait請求的順序

對於我們上面的**實現,我們主要來討論一下幾個訊號量的釋放順序。

生產者的wait訊號順序:我們的實現是先申請empty再申請對於快取區的訪問,這個順序如果顛倒有:

//生產者

wait

( visit )

;wait

( empty );.

....

signal

( visit )

;signal

( full )

;

這樣的顛倒會導致死鎖的危險,如果沒有空閒的快取區,生產者獲得了對快取區的訪問權,但是無法生產,wait(empty)阻塞,而消費者wait(full)成功,但是無法訪問快取區,這時生產者等待消費者處理資源後產生新的empty,消費者等待生產者釋放對於快取區的訪問,產生死鎖。

同理當我們調換對於消費者的wait順序時也有相同的隱患。

//消費者

wait

( visit )

;wait

( full );.

....

..signal

( visit )

;signal

( empty )

;

如果快取區為空的時候,消費者獲取了對於快取區的訪問,但是由於wait(full)被阻塞,(沒有生產好的資料了),這時生產者進行生產,首先獲取了wait(empty),但是沒有對於快取區的訪問權了(wait(visit)阻塞),生產者等著消費者釋放對於快取的訪問,消費者等著生產者生產資料。產生了死鎖的隱患。

signal請求的順序

對於請求的釋放順序就沒有那麼多的顧慮了,因為其不存在對於資源的占用,所以釋放時的先後並無影響,即使存在依賴關係,在下乙個時間片中相應的資源也會被釋放,所以釋放的順序並無影響。

有兩類的程序,一類是讀者程序,讀者程序之間可以同時訪問資源,這種訪問是非阻塞的,還有一類程序是寫者程序,寫者程序對於資源的訪問是阻塞式的,寫者程序與讀者程序之間的訪問也是阻塞式的。也就是單個寫者程序在寫時不允許其他的程序對資源進行訪問。這裡的資源可以理解為檔案。讀寫程序之間並無順序。

首先還是訊號量的設定。

int visit=1;

//表示對於檔案資源的訪問

//--------以上是訊號量設定----------

int rn=0;

//由於讀程序之間是可以同時對資源進行訪問的,所以使用乙個int來對其訪問的程序數量進行記錄。

接下來是相關pv原語的實現(偽**描述)。

wait

(int

&s)}

signal

(int

&s)}

之後就是相關程序的實現了。

//寫程序

writer()

}//讀程序

reader()

}

雖然上面實現了基本的讀寫程序的並行處理,但是顯然在讀程序的操作中存在乙個錯誤,就是rn的操作,這裡的rn顯然是乙個臨界資源,我們對其訪問的時候應該注意互斥訪問。

所以正確的實現如下:

//讀程序

int readnsign=1;

//增加乙個對讀程序計數的訊號量,保證對其互斥訪問。

reader()

}

這樣就實現了標準的程序並行處理。

5位哲學家圍繞圓桌而坐,反覆思考和進餐。但是只有5只碗和筷子,放置如圖所示,只有當哲學家同時拿起碗邊的2只筷子時,才能進餐。請用記錄型訊號量進行同步。

這裡的互斥訊號量也就是桌上的筷子,抽象一下就是每個執行緒需要兩個資源才能運作,但是資源的數量有限,如果同時請求只能滿足每個程序乙個資源的訪問需求。但是每個程序需要兩個資源才能進行工作,所以發生死鎖的概率極大。

要解決這一問題需要乙個程序打破這個請求迴圈,也就是至少滿足其中乙個程序的請求,這樣當這個程序完成執行後,釋放相關的資源後,其他的程序便可以依次的請求到資源完成工作。

下面是相關的偽**描述:

//訊號量描述

int sign[5]

=;//表示五個資源都是可以訪問的。

philosopher

(int i)

}

最後乙個哲學家有:

philosopher

(int i)

}

相當於所有的人都先去搶他們右手的筷子,左手的筷子被左邊的人作為右手的筷子搶去,但是最後一人去搶的是左手的筷子,也就是和左邊的人搶筷子,右邊的筷子空缺,沒有人搶,所以只要他搶到左邊的筷子,兩個筷子的資源就滿足了,就可以進行工作了。

其實這個問題的根源還是要一次性的獲得所有的資源,不然程序無法工作,所以也可以試試and型別的訊號量,對於程序資源進行一次性的分配,這樣一次請求之後程序就可以進行工作了。

對於程序同步問題的處理關鍵還是在臨界資源的設定與相關訊號量的分配處理與釋放處理上。有幾個臨界資源,每個臨界資源什麼時候釋放,什麼時候請求,以及相關的邏輯處理,原語的實現等等都應圍繞臨界資源與其訊號量展開。

作業系統 程序同步

臨界資源 critical resouce 臨界區 critical section 硬體同步機制 訊號量機制 訊號量的應用 管程3使用多道批處理系統不僅能有效的改善資源的利用率,還可以顯著地提高系統的吞吐量,但同時會使系統變得更加複雜,會使程式的執行結果存在不確定性。所以必須引入程序同步機制從而保...

作業系統 程序同步

引入程序 提高了資源的利用率和系統的吞吐量 程序的非同步性 會給系統造成混亂 程序同步基本概念 1,兩種形式的制約關係 a 間接相互制約 ab兩程序爭用一台印表機 b 直接相互制約 a程序放資料 緩衝區 b程序從緩衝區取資料 2,臨界資源 硬體臨界資源 軟體臨界資源 印表機,磁帶機,緩衝區。3,臨界...

作業系統 程序同步

ipc.件 include include include include include include include define bufsz 256 建立或獲取 ipc 的一組函式的原型說明 int get ipc id char proc file,key t key char set s...