試利用記錄性信號量寫出一個不會出現死鎖的哲學家進餐問題的算法
等一段時間再重復整個過程。
分析:當出現以下情形,在某一個瞬間,所有的哲學家都同時啟動這個算法,拿起左側的筷
子,而看到右側筷子不可用,又都放下左側筷子,等一會兒,又同時拿起左側筷子……如此
這樣永遠重復下去。對於這種情況,所有的程序都在運行,但卻無法取得進展,即出現飢餓,
所有的哲學家都吃不上飯。
(2) 描述一種沒有人餓死(永遠拿不到筷子)算法。
考慮了四種實現的方式(A、B、C、D):
A.原理:至多只允許四個哲學家同時進餐,以保證至少有一個哲學家能夠進餐,最終總會釋
放出他所使用過的兩支筷子,從而可使更多的哲學家進餐。以下將room 作為信號量,只允
許4 個哲學家同時進入餐廳就餐,這樣就能保證至少有一個哲學家可以就餐,而申請進入
餐廳的哲學家進入room 的等待隊列,根據FIFO 的原則,總會進入到餐廳就餐,因此不會
出現餓死和死鎖的現象。
偽碼:
semaphore chopstick[5]={1,1,1,1,1};
semaphore room=4;
void philosopher(int i)
{
while(true)
{
think();
wait(room); //請求進入房間進餐
wait(chopstick[i]); //請求左手邊的筷子
wait(chopstick[(i+1)%5]); //請求右手邊的筷子
eat();
signal(chopstick[(i+1)%5]); //釋放右手邊的筷子
signal(chopstick[i]); //釋放左手邊的筷子
signal(room); //退出房間釋放信號量room
}
}
B.原理:僅當哲學家的左右兩支筷子都可用時,才允許他拿起筷子進餐。
方法1:利用AND 型信號量機制實現:根據課程講述,在一個原語中,將一段代碼同時需
要的多個臨界資源,要么全部分配給它,要么一個都不分配,因此不會出現死鎖的情形。當
某些資源不夠時阻塞調用進程;由於等待隊列的存在,使得對資源的請求滿足FIFO 的要求,
因此不會出現飢餓的情形。
偽碼:
semaphore chopstick[5]={1,1,1,1,1};
void philosopher(int I)
{
while(true)
{
think();
Swait(chopstick[(I+1)]%5,chopstick[I]);
eat();
Ssignal(chopstick[(I+1)]%5,chopstick[I]);
}
}
方法2:利用信號量的保護機制實現。通過信號量mutex對eat()之前的取左側和右側筷
子的操作進行保護,使之成為一個原子操作,這樣可以防止死鎖的出現。
偽碼:
semaphore mutex = 1 ;
semaphore chopstick[5]={1,1,1,1,1};
void philosopher(int I)
{
while(true)
{
think();
wait(mutex);
wait(chopstick[(I+1)]%5);
wait(chopstick[I]);
signal(mutex);
eat();
signal(chopstick[(I+1)]%5);
signal(chopstick[I]);
}
}