# 僵局,第 3 部分:餐飲哲學家
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Deadlock%2C-Part-3%3A-Dining-Philosophers>
## 背景故事

所以你讓你的哲學家坐在桌子周圍,想要吃一些意大利面(或其他任何東西),他們真的很餓。每個哲學家本質上是相同的,意味著每個哲學家都有基于另一個哲學家的相同指令集,即你不能告訴每個甚至哲學家做一件事,每個奇怪的哲學家做另一件事。
## 解決方案失敗
## 左右僵局
我們做什么?我們來試試一個簡單的解決方案
```c
void* philosopher(void* forks){
info phil_info = forks;
pthread_mutex_t* left_fork = phil_info->left_fork;
pthread_mutex_t* right_fork = phil_info->right_fork;
while(phil_info->simulation){
pthread_mutex_lock(left_fork);
pthread_mutex_lock(right_fork);
eat(left_fork, right_fork);
pthread_mutex_unlock(left_fork);
pthread_mutex_unlock(right_fork);
}
}
```
但這遇到了問題!如果每個人拿起他們的左叉并且正在他們的右叉上等待怎么辦?我們已經使該計劃陷入僵局。重要的是要注意,死鎖不會一直發生,并且隨著哲學家數量的增加,這種解決方案死鎖的可能性會下降。值得注意的是,最終這個解決方案將陷入僵局,讓線程挨餓哪個壞。
## 的 tryLock?更喜歡活鎖
所以現在你正在考慮打破其中一個 coffman 條件。我們有
* 相互排斥
* 沒有先發制人
* 等等
* 循環等待
好吧,我們不能讓兩個哲學家同時使用一個分叉,相互排斥是不合適的。在我們當前的簡單模型中,一旦他/她掌握它,我們就不能讓哲學家放開互斥鎖,所以我們現在就把這個解決方案拿出來 - 底部有一些注釋。有關此解決方案的頁面讓我們休息一下等待!
```c
void* philosopher(void* forks){
info phil_info = forks;
pthread_mutex_t* left_fork = phil_info->left_fork;
pthread_mutex_t* right_fork = phil_info->right_fork;
while(phil_info->simulation){
pthread_mutex_lock(left_fork);
int failed = pthread_mutex_trylock(right_fork);
if(!failed){
eat(left_fork, right_fork);
pthread_mutex_unlock(right_fork);
}
pthread_mutex_unlock(left_fork);
}
}
```
現在我們的哲學家拿起左叉并試圖抓住右邊。如果它可用,他們會吃。如果它不可用,他們將左叉放下并重試。沒有死鎖!
但有個問題。如果所有的哲學家同時拿起他們的左手,試圖抓住他們的權利,把他們的左手放下,拿起他們的左手,試圖抓住他們的權利......我們現在已經解決了我們的解決方案!我們可憐的哲學家仍在挨餓,所以讓我們給他們一些適當的解決方案。
## 可行的解決方案
## 仲裁員(天真和高級)。
天真的仲裁者解決方案有一個仲裁員(例如互斥)。讓每個哲學家都要求仲裁員吃飯。這種解決方案允許一個哲學家一次吃。當他們完成后,另一位哲學家可以請求允許進食。
這可以防止死鎖,因為沒有循環等待!沒有哲學家必須等待任何其他哲學家。
高級仲裁者解決方案是實施一個類,確定哲學家的分叉是否在仲裁員的掌握之中。如果他們是,他們把它們交給哲學家,讓他吃,并把分叉拿回來。這有額外的好處,可以讓多個哲學家同時吃。
### 問題:
* 這些解決方案很慢
* 他們有一個單點的失敗,仲裁員使其成為瓶頸
* 仲裁者也需要公平,并能夠在第二個解決方案中確定死鎖
* 在實際系統中,仲裁員傾向于將重復的分叉交給那些因為過程調度而吃的哲學家
## 離開桌子(Stallings 的解決方案)
為什么第一個解決方案陷入僵局?那么有 n 個哲學家和 n 個筷子。如果餐桌上只有 1 個 philsopher 怎么辦?我們可以陷入僵局嗎?沒有。
2 個 philsophers 怎么樣? 3? ......你可以看到它的發展方向。斯托林斯的解決方案說要將哲學家從桌子上移除,直到陷入僵局為止 - 想想桌上哲學家的神奇數量是多少。在實際系統中這樣做的方法是通過信號量并讓一定數量的哲學家通過。
### Problems:
* 該解決方案需要大量的上下文切換,這對 CPU 來說非常昂貴
* 你需要事先知道資源的數量,才能讓那些哲學家知道
* 再次優先考慮已經吃過的過程。
## 部分訂購(Dijkstra 的解決方案)
這是 Dijkstra 的解決方案(他是在考試中提出這個問題的人)。為什么第一個解決方案陷入僵局? Dijkstra 認為最后一個拿起左叉的哲學家(使解決方案陷入僵局)應該選擇他的權利。他用數字 1..n 來完成它,并告訴每個哲學家拿起他的較低數字叉。
讓我們再次遇到死鎖情況。每個人都試圖先拿起他們的低號碼叉。哲學家 1 獲得分叉 1,哲學家 2 獲得分叉 2,依此類推,直到我們到達哲學家 n。他們必須在 fork 1 和 n 之間進行選擇。 fork 1 已被哲學家 1 所阻擋,所以他們無法拿起那個分叉,這意味著他不會拿起分叉。我們已經打破了循環等待!意味著死鎖是不可能的。
### Problems:
* 在獲取任何資源之前,哲學家需要按順序了解資源集。
* 您需要為所有資源定義部分訂單。
* 優先考慮已經吃過的哲學家。
## 高級解決方案
還有許多更為先進的解決方案,非詳盡列表包括
* 清潔/臟叉(錢德拉/米斯拉解決方案)
* 演員模型(其他消息傳遞模型)
* 超級仲裁員(復雜的管道)
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話