4. 編程練習

哲學家就餐問題。這是由計算機科學家Dijkstra提出的經典死鎖場景。

原版的故事裡有五個哲學家(不過我們寫的程序可以有N個哲學家),這些哲學家們只做兩件事--思考和吃飯,他們思考的時候不需要任何共享資源,但是吃飯的時候就必須使用餐具,而餐桌上的餐具是有限的,原版的故事裡,餐具是叉子,吃飯的時候要用兩把叉子把麵條從碗裡撈出來。很顯然把叉子換成筷子會更合理,所以:一個哲學家需要兩根筷子才能吃飯。

現在引入問題的關鍵:這些哲學家很窮,只買得起五根筷子。他們坐成一圈,兩個人的中間放一根筷子。哲學家吃飯的時候必須同時得到左手邊和右手邊的筷子。如果他身邊的任何一位正在使用筷子,那他只有等着。

假設哲學家的編號是A、B、C、D、E,筷子編號是1、2、3、4、5,哲學家和筷子圍成一圈如下圖所示:

圖 35.2. 哲學家問題

哲學家問題

每個哲學家都是一個單獨的綫程,每個綫程循環做以下動作:思考rand()%10秒,然後先拿左手邊的筷子再拿右手邊的筷子(筷子這種資源可以用mutex表示),有任何一邊拿不到就一直等着,全拿到就吃飯rand()%10秒,然後放下筷子。

編寫程序仿真哲學家就餐的場景:

Philosopher A fetches chopstick 5
Philosopher B fetches chopstick 1
Philosopher B fetches chopstick 2
Philosopher D fetches chopstick 3
Philosopher B releases chopsticks 1 2
Philosopher A fetches chopstick 1
Philosopher C fetches chopstick 2
Philosopher A releases chopsticks 5 1
...

分析一下,這個過程有沒有可能產生死鎖?調用usleep(3)函數可以實現微秒級的延時,試着用usleep(3)加快仿真的速度,看能不能觀察到死鎖現象。然後修改上述算法避免產生死鎖。