哲學家就餐問題詳解
2.23 哲學家就餐問題
1965年由Dijkstra提出
問題描述
- 5個哲學家圍坐圓桌
- 5只餐叉間隔擺放
- 哲學家行為為思考或進餐
- 哲學家進餐必須同時使用兩邊的餐叉
- 思考時蔣餐叉放回原處
- 兩個哲學家不使用同一把叉子
- 儘量避免死鎖和飢餓
如圖
方案一 取左叉
都去拿左邊的叉子,死鎖
semaphore fork[5] = {1, 1, 1, 1, 1};
void main()
{
cobegin {philosopher(0);
philosopher(1);
philosopher(2);
philosopher(3);
philosopher(4);
}coend;
}
void philosopher(int i)
{
while(true) {
think; //思考
wait(fork[i]); //拿起左邊的叉子
wait(fork[(i+1)%5]); //拿起右邊的叉子
eat();
signal(fork[i]); //放回左邊的叉子
signal(fork[(i+1)%5]); //放回右邊的叉子
}
}
方案二
請求同時拿兩個叉子,被佔則等待隨機事件再請求,可能活鎖
semaphore fork[5] = {1, 1, 1, 1, 1};
void main()
{
cobegin {philosopher(0);
philosopher(1);
philosopher(2);
philosopher(3);
philosopher(4);
}coend;
}
void philosopher(int i)
{
while(true) {
think; //思考
wait(fork[i]); //拿起左邊的叉子
timeout(wait(fork[(i+1)%5], [0, T]) //若右邊的叉子被佔用,則放下左邊叉,等待一段隨機時間後再拿
eat();
signal(fork[i]); //放回左邊的叉子
signal(fork[(i+1)%5]); //放回右邊的叉子
}
}
方案三 資源分級
為資源(這裡是餐叉)分配一個偏序(partial order)或者分級(hierarchy)的關係,並約定所有資源都按照這種順序獲取,按相反順序釋放,而且保證不會有兩個無關資源同時被同一項工作所需要
① 為餐叉編號
- 就餐前,先取用編號較低的餐叉,再取用編號較高的餐叉
- 就餐畢,先放下編號較高的餐叉,再放下編號較低的餐叉
semaphore fork[5] = {1, 1, 1, 1, 1};
void main()
{
cobegin {philosopher(0);
philosopher(1);
philosopher(2);
philosopher(3);
philosopher(4);
}coend;
}
void philosopher(int i)
{
while(true) {
think(); //思考
if (i != 4) {
wait(fork[i]); wait(fork[(i+1)%5]);} //先左後右
else {
wait(fork[(i+1)%5]); wait(fork[i]);} //先右後左
eat();
if (i != 4) {
signal(fork[(i+1)%5]); signal(fork[i]);} //先右後左
else {
signal(fork[i]); signal(fork[(i+1)%5]);} //先左後右
}
}
② 為哲學家編號
- 奇數號的哲學家必須首先拿左邊的餐叉
- 偶數號的哲學家必須首先拿右邊的餐叉
semaphore fork[5] = {1, 1, 1, 1, 1};
void main()
{
cobegin {philosopher(0);
philosopher(1);
philosopher(2);
philosopher(3);
philosopher(4);
}coend;
}
void philosopher(int i)
{
while(true) {
think(); //思考
if (i % 2 != 0) {
wait(fork[i]); wait(fork[(i+1)%5]);} //先左後右
else {
wait(fork[(i+1)%5]); wait(fork[i]);}
eat();
signal(fork[(i+1)%5]); //先右後左
signal(fork[i]);
}
}
方案四 服務生方法
- 引入一個餐廳服務生,哲學家必須經過他的允許才能拿起餐叉
- 最多允許4個哲學家同時進食
semaphore fork[5] = {1, 1, 1, 1, 1}, room = 4;
void main()
{
cobegin {philosopher(0);
philosopher(1);
philosopher(2);
philosopher(3);
philosopher(4);
}coend;
}
void philosopher(int i)
{
while(true) {
think; //思考
wait(room); //佔據就餐位置
wait(fork[i]); //拿起左邊的叉子
wait(fork[(i+1)%5]); //拿起右邊的叉子
signal(fork[i]); //放回左邊的叉子
signal(fork[(i+1)%5]); //放回右邊的叉子
signal(room); //釋放就餐位置
}
}
引申:And型訊號量集
- 在一個原語中申請需要的多個臨界資源,要麼全部分,要麼一個都不分配
- AND型訊號量集P原語為Swait(Simultaneous Wait),V原語為Ssignal(Simultaneous Signal)。
- Swait(S1, S2, …, Sn)
- Ssignal(S1, S2, …, Sn)
管程方案
monitor dining controller;
cond ForkReady [5]; /*condition variable for synchronization */
boolean fork[ 5]={ true } ; /*availability status of each fork*/
void get_forks (int pid) /*pid is the philosopher id number */
{
int left = pid;
int right =(++pid)%5;
/*grant the left fork*/
if( ! fork [ left])
cwait(ForkReady [ left] ); /*queue on condition variable */
fork [ left]= false ;
/*grant the right fork*/
if( ! fork [ right] )
cwait(ForkReady [right] );
/*queue on condition variable */
fork [ right] = false;
}
void release_forks ( int pid){
int left = pid;
int right =(++pid)%5;
/*release the left fork*/
if( empty (ForkReady [ leftl) /*no one is waiting for this fork */
fork [ left] = true;
else /*awaken a process waiting on this fork */
csignal (ForkReady [ left]);
/*release the right fork*/
if (empty (ForkReady [right]) /*no one is waiting for this fork*/
fork [ right]= true;
else /*awaken a process waiting on this fork*/
csignal (ForkReady [right] );
}
void philosopher [ k=0 to 4] /*the five philosopher clients */
{
while (true){
<think>;
get_forks (k); /*client requests two forks via monitor * /
<eat spaghetti>;
release_forks (k); /*client releases forks via the monitor */
}
}
相關文章
- Linux程式設計:程式同步問題之哲學家就餐問題Linux程式設計
- java實現pv操作 -------哲學家問題Java
- 無名訊號量實現哲學家問題
- 用c++設計哲學家進餐問題的求解C++
- 看看哲學家如何使用“遊戲”這一概念遊戲
- JavaScript 揹包問題詳解JavaScript
- 詳解JS跨域問題JS跨域
- Java中文問題詳解(轉)Java
- 哲學家啟動研究 :數學是發明還是發現?- dailynousAI
- AI助攻「菜鳥數學家」解決忙碌海狸問題,陶哲軒轉發分享AI
- 《哲學家們都幹了些什麼》讀書筆記筆記
- TCP協議粘包問題詳解TCP協議
- CAS原理分析及ABA問題詳解
- 字串編輯距離問題詳解字串
- LILO啟動問題詳解 (轉)
- 哲學筆記筆記
- 《數學沉思錄》的筆記-第二章神祕學:命理學家和哲學家筆記
- flutter安裝詳解--初體驗--問題解決Flutter
- 混合專家模型 (MoE) 詳解模型
- 密碼學專家揭示Telegram Passport中的安全問題密碼學Passport
- 去留無意,去留爺爺,是去還是留,這是一個哲學問題?
- web開發的跨域問題詳解Web跨域
- Python異常 ValueError的問題詳解PythonError
- axios請求JSON問題詳解iOSJSON
- Java中文問題詳解(高手必讀) (轉)Java
- 解決問題oracle學習篇Oracle
- 一文詳解資料科學家的必備技能資料科學
- 哲學筆記——老子筆記
- 雲解析專家講解DNS解析生效時間問題DNS
- 程式設計藝術家經典試題解讀:猜生日問題程式設計
- 多執行緒併發安全問題詳解執行緒
- web安全機制問題詳解之二:CSRFWeb
- 前端進階課程之跨域問題詳解前端跨域
- mount命令詳解及常見問題彙總
- JavaScript 面試中常見演算法問題詳解JavaScript面試演算法
- PHP檔案讀寫鎖的問題詳解PHP
- 解決「問題」,不要解決問題
- 【原創】視訊+文字:詳解VBA解決數獨問題