作業系統之經典程序同步問題
這裡介紹三中程序同步問題:
1.生產者-消費者問題
2.讀者-寫者問題
3.哲學家進餐問題
一、生產者-消費者問題
1.問題描述:生產者-消費者模型描述的是有一群生產者程序在生產產品,並將這些產品提供給消費者程序併發進行,具備併發程式的典型特徵。PCM為使生產者程序和消費者程序併發進行,在它們之間設定一個具有多個緩衝區的緩衝池生產者程序可以將其所生產的產品放入一個緩衝區中,消費者程序可以從一個緩衝區中取得產品去消費。儘管所有的生產者程序和消費者程序都是以非同步方式執行的,但他們之間必須保持同步,既不允許消費者程序從空的緩衝區中拿產品,也不允許生產者程序向滿緩衝區中放產品。
2.問題分析:我們可以利用一個數組來表示上述的具有n各緩衝單元的緩衝區。用輸入指標in作寫指標,每當生產者程序生產並投放一個產品時,in加1;同理,out指標作為讀指標,每當消費者拿走一個產品時out便加1。由於緩衝區是迴圈佇列,則加1寫成,in=(in+1)mod n,out同理。當(in+1)mod n==out時,緩衝區滿,當in==out時,緩衝區為空。此外還引入了count,當生產者生產並放入時加1,消費者拿走時則減1.
3.程式描述:
共享變數:
程式虛擬碼:int n, buffer[n]; int in, out; //in,out[0,n-1] int count; //count[0,n]
void producer() {
producer an item in nextp;
while (count == n) {
buffer[in] = nextp;
in = (in + 1)mod n;
count++;
}
void consumer() {
while (count==0) {
nextc = buffer[out];
out = (out + 1)mod n;
count--;
consumer the item in nextc;
}
4.利用記錄型訊號量解決PC問題
int mutex = 0, empty = n, full = 0; int buffer[n]; int in = 0, out = 0; void producer() { producer an item, nextp;//nextp為生產的產品 wait(empty); wait(mutex); buffer[in] = nextp; in = (in + 1)mod n; signal(mutex); signal(full); } void consumer() { wait(full); wait(mutex); nextc = buffer[out]; out = (out + 1)mod n; signal(mutex); signal(empty); consumer nextc; }
注:在記錄型訊號中wait(),和signal()操作如下:
void wait(s) { //s為訊號量
s--;
if (s < 0) {
block(s,L)//阻塞
}
}
void signal(s) {
s++;
if (s <=0) {
wakeup(s, L);//喚醒
}
需要注意的是:每個程式中用於實現互斥的wait(mutex)和signal(mutex)必須成對出現。注意wait(empty)在生產者程序中,每個程式中多個wait操作不可顛倒,否則容易發生死鎖的現象。
二、讀者-寫者問題
1.問題描述:一個數據檔案或記錄可被多個程序所共享,將其中只要求讀該檔案的程序稱為讀者,其他程序稱為寫者。多個讀者程序和多個寫者程序在某個時間段內對該檔案資源進行非同步操作。限制如下:
寫-寫互斥、讀-寫互斥、讀-讀允許
2.利用記錄型訊號量解決讀者-寫者問題
int rmutex = 1, wmutex = 1;
int readcount = 0;
void reader() {
do {
wait(rmutex);//各讀者互斥的通過門禁,進入讀書室
//第一個讀者進入讀書室時需要開啟禁止寫者進入的訊號
if (readcount == 0) {
wait(wmutex);
}
readcount++;
signal(rmutex);
perform read operation;//讀者閱讀,此時進行的讀操作無需互斥
wait(rmutex);//互斥的通過門禁,離開圖書室
readcount--;
//最後一個讀者離開時需要關閉禁止寫者進入的訊號
if (readcount == 0) {
signal(wmutex);
}
signal(rmutex);
} while (true);
}
void writer() {
do {
wait(wmutex);
perform write operation;
signal(wmutex);
} while (true);
}
三、哲學家進餐問題
1.問題描述:有五位哲學家,它們的生活方式是交替的進行思考和進餐。哲學家門共用一張圓桌,分別坐在周圍的五張椅子上。在圓桌上有五隻碗和五根筷子,平時哲學家進行思考,飢餓的時候檢視取其左右的靠他最近的筷子,只有當拿到兩根筷子時才能進餐。(老師給我們講的版本是刀和叉呀,笑哭...)
2.利用記錄型訊號解決哲學家進餐問題
int chopstick[5] = {1,1,1,1,1};
do {
wait(chopstick[i]);
wait(chopstick[(i + 1mod 5)]);
eat;
signal(chopstick[i]);
signal(chopstick[(i + 1mod 5)]);
think;
} while (true);
該方法存在的問題:當哲學家都成功的拿起左邊的筷子時都處於“等待”狀態,進而發生死鎖的問題。
3.解決策略:
1)至多隻允許四位哲學系同時去拿左邊的筷子,最終能保證至少有一位哲學家能夠進餐,並在用完時釋放出他用過的兩根筷子。
2)當哲學家的左、右兩根筷子均可用時,才允許他拿起筷子進餐。
3)規定奇數號哲學家先拿起他左邊的筷子,然後再去拿他右邊的筷子;而偶數號則相反。按此規定,總會有一位哲學家能進餐,並在使用完後釋放筷子。
4.利用AND訊號量機制解決哲學家進餐問題(上述的第二種方法)
int chopstick[5] = { 1,1,1,1,1 };
do {
think;
wait(chopstick[(i + 1)mod 5], chopstick[i]);
eat;
signal(chopstick[(i + 1)mod 5], chopstick[i]);
} while (true);