導航:首頁 > 編程語言 > 哲學家就餐java

哲學家就餐java

發布時間:2022-11-19 21:15:48

① 100分 解決java 哲學家問題

加一個main方法噻
public static void main(String args[]){
Dining d=new Dining();
d.setVisible(true);
}

呵呵,這個小程序貌似在講解線程的同步和死鎖
問題很經典,不過如果用銀行轉賬那個來舉例應該更容易理解

② 解決哲學家用餐問題有多少種方法

哲學家就餐問題

1965年,Dijkstra提出並解決了一個他稱之為哲學家就餐的同步問題。從那時起,每個發明新的同步原語的人都希望通過解決哲學家就餐問題來 展示其同步原語的精妙之處。這個問題可以簡單地描述如下:五個哲學家圍坐在一張圓桌周圍,每個哲學家面前都有一盤通心粉。由於通心粉很滑,所以需要兩把叉 子才能夾住。相鄰兩個盤子之間放有一把叉子,餐桌如圖2-44所示。

哲學家的生活中有兩種交替活動時段:即吃飯和思考(這只是一種抽象,即對哲學家而言其他活動都無關緊要)。當一個哲學家覺得餓了時,他就試圖分兩次 去取其左邊和右邊的叉子,每次拿一把,但不分次序。如果成功地得到了兩把叉子,就開始吃飯,吃完後放下叉子繼續思考。關鍵問題是:能為每一個哲學家寫一段 描述其行為的程序,且決不會死鎖嗎?(要求拿兩把叉子是人為規定的,我們也可以將義大利面條換成中國菜,用米飯代替通心粉,用筷子代替叉子。)

圖2-45給出了一種直觀的解法。過程take_fork將一直等到所指定的叉子可用,然後將其取用。不過,這種顯然的解法是錯誤的。如果五位哲學家同時拿起左面的叉子,就沒有人能夠拿到他們右面的叉子,於是發生死鎖。

我們可以將這個程序修改一下,這樣在拿到左叉後,程序要查看右面的叉子是否可用。如果不可用,則該哲學家先放下左叉,等一段時間,再重復整個過程。 但這種解法也是錯誤的,盡管與前一種原因不同。可能在某一個瞬間,所有的哲學家都同時開始這個演算法,拿起其左叉,看到右叉不可用,又都放下左叉,等一會 兒,又同時拿起左叉,如此這樣永遠重復下去。對於這種情況,所有的程序都在不停地運行,但都無法取得進展,就稱為飢餓(starvation)。(即使問 題不發生在義大利餐館或中國餐館,也被稱為飢餓。)

③ 200分求java實現哲學家就餐問題的程序,完整可以再加分

public class kuai {
String name;

boolean Enable = true;

public kuai(String name) {
this.name = name;
}

public synchronized void pickup(){
try {
while(Enable==false){
this.wait();
}
this.Enable =false;
}
catch (Exception e) {

}

}

public synchronized void putdown() {
this.Enable =true;
this.notifyAll();
}

public static void main(String args[]) {
kuai k1 = new kuai("筷子1號");
kuai k2 = new kuai("筷子2號");
kuai k3 = new kuai("筷子3號");
kuai k4 = new kuai("筷子4號");
kuai k5 = new kuai("筷子5號");

People p1 = new People("老大", k1, k2);
People p2 = new People("老二", k2, k3);
People p3 = new People("老三", k3, k4);
People p4 = new People("老四", k4, k5);
People p5 = new People("老幺", k5, k1);

p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
}
}

class People extends Thread {
String name;

kuai left;

kuai right;

public People(String name, kuai l, kuai r) {
this.name = name;
left = l;
right = r;
}

public void run() {
left.pickup();
System.out.println(name + " 眼明手快,以迅雷不及掩耳之勢一把抓起 "+left.name);
right.pickup();
System.out.println(name + " 眼明手快,以迅雷不及掩耳之勢一把抓起 "+right.name);
System.out.println(name + " 左右開弓,狼吞虎咽起來");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
System.out.println(name + " 酒足飯飽,打了個飽嗝,心滿意足的放下了 "+left.name+" 和 " +right.name);
left.putdown();
right.putdown();

}
}

別人做的,抄來的 :) 作者是:xy124

④ java線程問題

不管你是新程序員還是老手,你一定在面試中遇到過有關線程的問題。Java語言一個重要的特點就是內置了對並發的支持,讓Java大受企業和程序員的歡迎。大多數待遇豐厚的Java開發職位都要求開發者精通多線程技術並且有豐富的Java程序開發、調試、優化經驗,所以線程相關的問題在面試中經常會被提到。
在典型的Java面試中, 面試官會從線程的基本概念問起, 如:為什麼你需要使用線程, 如何創建線程,用什麼方式創建線程比較好(比如:繼承thread類還是調用Runnable介面),然後逐漸問到並發問題像在Java並發編程的過程中遇到了什麼挑戰,Java內存模型,JDK1.5引入了哪些更高階的並發工具,並發編程常用的設計模式,經典多線程問題如生產者消費者,哲學家就餐,讀寫器或者簡單的有界緩沖區問題。僅僅知道線程的基本概念是遠遠不夠的, 你必須知道如何處理死鎖,競態條件,內存沖突和線程安全等並發問題。掌握了這些技巧,你就可以輕松應對多線程和並發面試了。
許多Java程序員在面試前才會去看面試題,這很正常。因為收集面試題和練習很花時間,所以我從許多面試者那裡收集了Java多線程和並發相關的50個熱門問題。我只收集了比較新的面試題且沒有提供全部答案。想必聰明的你對這些問題早就心中有數了, 如果遇到不懂的問題,你可以用Google找到答案。若你實在找不到答案,可以在文章的評論中向我求助。

⑤ 哲學家就餐問題 (急,急,急!)

有五個哲學家圍坐在一圓桌旁,桌中央有一盤通心粉,每人面前有一隻空盤子,每兩人之間放一隻筷子每個哲學家的行為是思考,感到飢餓,然後吃通心粉.為了吃通心粉,每個哲學家必須拿到兩只筷子,並且每個人只能直接從自己的左邊或右邊去取筷子
#define N 5
void philosopher (int i) <BR>{
while (true)
{
思考;
取fork[i]; 取fork[(i+1) % 5];
進食;
放fork[i]; 放fork[(i+1) % 5];
}
}
為防止死鎖發生可採取的措施:
最多允許4個哲學家同時坐在桌子周圍僅當一個哲學家左右兩邊的筷子都可用時,才允許他拿筷子()給所有哲學家編號,奇數號的哲學家必須首先拿左邊的筷子,偶數號的哲學家則反之 為了避免死鎖,把哲學家分為三種狀態,思考,飢餓,進食,並且一次拿到兩只筷子,否則不拿.

哲學家就餐問題解法(1)
#define N 5
void philosopher (int i)
{
while (true)
{
思考;
取fork[i]; 取fork[(i+1) % 5];
進食;
放fork[i]; 放fork[(i+1) % 5];
}
}
哲學家就餐問題解法(2)
#define N 5
#define THINKING 0
#define HUNGRY 1
#define EATING 2
#typedef int semaphore;
int state[N];
semaphore mutex=1;
semaphore s[N];
void test(int i)
{
if (state[ i ] == HUNGRY)
&& (state [ (i-1) % 5] != EATING)
&& (state [ (i+1) % 5] != EATING)
{
state[ i ] = EATING;
V(&s[ i ]);
}
}
void philosopher (int i)
{ while (true)
{
思考;
P(&mutex);
state[i] = HUNGRY;
test(i);
V(&mutex);
P(&s[i]);
拿左筷子;
拿右筷子;
進食;
放左筷子;
放右筷子;
P(&mutex)
state[ i ] = THINKING;
test([i-1] % 5);
test([i+1] % 5);
V(&mutex);
}
}
state[ i ] = THINKING
s[ i ] = 0

-----------
粘貼的,其實我也不懂

⑥ 關於java打包 生成可執行文件 jar

呵呵 我剛做了 ! 例子就以我以前寫的那個哲學家就餐問題模擬(圖形界面)為例,這些代碼在我的空間上已經給出了. 編譯完哲學家就餐問題模擬的代碼後生成三個class文件,分別是Main.class, Philosopher.class, Chopsticks.class. 接下來把這三個文件放在同一個文件夾下,啟動cmd,進入到那個目錄.這里假設生成後的jar文件名為Test.jar,先運行 jar cvf Test.jar Main.class Philosopher.class Chopsticks.class 運行命令後得到以下輸出信息: 標明清單(manifest) 增加:Main.class(讀入= 4833) (寫出= 2541)(壓縮了 47%) 增加:Philosopher.class(讀入= 1857) (寫出= 1071)(壓縮了 42%) 增加:Chopsticks.class(讀入= 946) (寫出= 574)(壓縮了 39%) 在當前目錄下會生成一個Test.jar的文件.接下來,用解壓縮工具(如WinRAR)解壓Test.jar,在解壓出來的文件中有一個名為 META-INF 的文件來,打開它後會看到名為 MANIFEST.MF 的文件,用記事打開它,在它的最後面加入一行,內容為: Main-Class: Main (說明:在Main-Class:和Main之間有個空格,行的末尾不能有多餘的空格,也不在最後面有多餘的空行) Main-Class: 後面的內容要按實際情況來寫,因為我這里的可執行class文件名為Main.class,所以我才在後面寫Main. 假如你的可執行class的名為HelloWorld.class,那麼最後一行的內容該寫為 Main-Class: HelloWorld 接下來,把修改好的MANIFEST.MF文件拷貝,放在以前的那個文件夾(就是放有Main.class, Philosopher.class, Chopsticks.class這三個文件的文件夾)下,那麼現在該文件來下就有四個文件,分別為Main.class, Philosopher.class, Chopsticks.class 和MANIFEST.MF. 在cmd中進入到那個文件夾目錄,運行以下命令,這里假設要生成的jar文件還叫做Test.jar,你也可用其它名字: jar cvfm Test.jar MANIFEST.MF Main.class Philosopher.class Chopsticks.class 運行後得到以下輸出信息: 標明清單(manifest) 增加:Main.class(讀入= 4833) (寫出= 2541)(壓縮了 47%) 增加:Philosopher.class(讀入= 1857) (寫出= 1071)(壓縮了 42%) 增加:Chopsticks.class(讀入= 946) (寫出= 574)(壓縮了 39%) 可在文件夾下看到生成了Test.jar文件,雙擊它即可運行你的Java程序了.至此,所有步驟就完成了.

⑦ 哲學家進餐問題(在計算機操作系統方面的相關編程)

操作系統並發和互斥:哲學家進餐問題和理發師問題

1. 哲學家進餐問題:
(1) 在什麼情況下5 個哲學家全部吃不上飯?
考慮兩種實現的方式,如下:
A.
演算法描述:
void philosopher(int i) /*i:哲學家編號,從0 到4*/
{
while (TRUE) {
think( ); /*哲學家正在思考*/
take_fork(i); /*取左側的筷子*/
take_fork((i+1) % N); /*取左側筷子;%為取模運算*/
eat( ); /*吃飯*/
put_fork(i); /*把左側筷子放回桌子*/
put_fork((i+1) % N); /*把右側筷子放回桌子*/
}
}
分析:假如所有的哲學家都同時拿起左側筷子,看到右側筷子不可用,又都放下左側筷子,
等一會兒,又同時拿起左側筷子,如此這般,永遠重復。對於這種情況,即所有的程序都在
無限期地運行,但是都無法取得任何進展,即出現飢餓,所有哲學家都吃不上飯。
B.
演算法描述:
規定在拿到左側的筷子後,先檢查右面的筷子是否可用。如果不可用,則先放下左側筷子,
等一段時間再重復整個過程。
分析:當出現以下情形,在某一個瞬間,所有的哲學家都同時啟動這個演算法,拿起左側的筷
子,而看到右側筷子不可用,又都放下左側筷子,等一會兒,又同時拿起左側筷子……如此
這樣永遠重復下去。對於這種情況,所有的程序都在運行,但卻無法取得進展,即出現飢餓,
所有的哲學家都吃不上飯。
(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]);
}
}
C. 原理:規定奇數號的哲學家先拿起他左邊的筷子,然後再去拿他右邊的筷子;而偶數號
的哲學家則相反.按此規定,將是1,2號哲學家競爭1號筷子,3,4號哲學家競爭3號筷子.即
五個哲學家都競爭奇數號筷子,獲得後,再去競爭偶數號筷子,最後總會有一個哲學家能獲
得兩支筷子而進餐。而申請不到的哲學家進入阻塞等待隊列,根FIFO原則,則先申請的哲
學家會較先可以吃飯,因此不會出現餓死的哲學家。
偽碼:
semaphore chopstick[5]={1,1,1,1,1};
void philosopher(int i)
{
while(true)
{
think();
if(i%2 == 0) //偶數哲學家,先右後左。
{
wait (chopstick[ i + 1 ] mod 5) ;
wait (chopstick[ i]) ;
eat();
signal (chopstick[ i + 1 ] mod 5) ;
signal (chopstick[ i]) ;
}
Else //奇數哲學家,先左後右。
{
wait (chopstick[ i]) ;
wait (chopstick[ i + 1 ] mod 5) ;
eat();
signal (chopstick[ i]) ;
signal (chopstick[ i + 1 ] mod 5) ;
}
}
D.利用管程機制實現(最終該實現是失敗的,見以下分析):
原理:不是對每隻筷子設置信號量,而是對每個哲學家設置信號量。test()函數有以下作
用:
a. 如果當前處理的哲學家處於飢餓狀態且兩側哲學家不在吃飯狀態,則當前哲學家通過
test()函數試圖進入吃飯狀態。
b. 如果通過test()進入吃飯狀態不成功,那麼當前哲學家就在該信號量阻塞等待,直到
其他的哲學家進程通過test()將該哲學家的狀態設置為EATING。
c. 當一個哲學家進程調用put_forks()放下筷子的時候,會通過test()測試它的鄰居,
如果鄰居處於飢餓狀態,且該鄰居的鄰居不在吃飯狀態,則該鄰居進入吃飯狀態。
由上所述,該演算法不會出現死鎖,因為一個哲學家只有在兩個鄰座都不在進餐時,才允
許轉換到進餐狀態。
該演算法會出現某個哲學家適終無法吃飯的情況,即當該哲學家的左右兩個哲學家交替
處在吃飯的狀態的時候,則該哲學家始終無法進入吃飯的狀態,因此不滿足題目的要求。
但是該演算法能夠實現對於任意多位哲學家的情況都能獲得最大的並行度,因此具有重要
的意義。
偽碼:
#define N 5 /* 哲學家人數*/
#define LEFT (i-1+N)%N /* i的左鄰號碼 */
#define RIGHT (i+1)%N /* i的右鄰號碼 */
typedef enum { THINKING, HUNGRY, EATING } phil_state; /*哲學家狀態*/
monitor dp /*管程*/
{
phil_state state[N];
semaphore mutex =1;
semaphore s[N]; /*每個哲學家一個信號量,初始值為0*/
void test(int i)
{
if ( state[i] == HUNGRY &&state[LEFT(i)] != EATING &&
state[RIGHT(i)] != EATING )
{
state[i] = EATING;
V(s[i]);
}
}
void get_forks(int i)
{
P(mutex);
state[i] = HUNGRY;
test(i); /*試圖得到兩支筷子*/
V(mutex);
P(s[i]); /*得不到筷子則阻塞*/
}
void put_forks(int i)
{
P(mutex);
state[i]= THINKING;
test(LEFT(i)); /*看左鄰是否進餐*/
test(RIGHT(i)); /*看右鄰是否進餐*/
V(mutex);
}
}
哲學家進程如下:
void philosopher(int process)
{
while(true)
{
think();
get_forks(process);
eat();
put_forks(process);
}
}
2.理發師問題:一個理發店有一個入口和一個出口。理發店內有一個可站5 位顧客的站席
區、4 個單人沙發、3 個理發師及其專用理發工具、一個收銀台。新來的顧客坐在沙發上等
待;沒有空沙發時,可在站席區等待;站席區滿時,只能在入口外等待。理發師可從事理
發、收銀和休息三種活動。理發店的活動滿足下列條件:
1)休息的理發師是坐地自己專用的理發椅上,不會佔用顧客的沙發;
2)處理休息狀態的理發師可為在沙發上等待時間最長的顧客理發;
3)理發時間長短由理發師決定;
4)在站席區等待時間最長的顧客可坐到空閑的理發上;
5)任何時刻最多隻能有一個理發師在收銀。
試用信號量機制或管程機制實現理發師進程和顧客進程。
原理:
(1)customer 進程:
首先檢查站席區是否已滿(stand_capacity),若滿選擇離開,否則進入站席區,即進入
理發店。在站席區等待沙發的空位(信號量sofa),如果沙發已滿,則進入阻塞等待隊列,
直到出現空位,在站席區中等待時間最長的顧客離開站席區(stand_capacity)。坐到沙
發上,等待理發椅(barber_chair),如果理發椅已滿,則進入阻塞等待隊列,直到出現
空位,在沙發上等待時間最長的顧客離開沙發(釋放信號量sofa)。坐到理發椅上,釋放
准備好的信號(customer_ready),獲得該理發師的編號(0~1 的數字)。等待理發師理
發結束(finished[barber_number])。在離開理發椅之前付款(payment),等待收據
(receipt),離開理發椅(leave_barberchair)。最後離開理發店。
這里需要注意幾點:
a) 首先是幾個需要進行互斥處理的地方,主要包括:進入站席區、進入沙發、進入理發椅
和付款幾個地方。
b) 通過barber_chair 保證一個理發椅上最多隻有一名顧客。但這也不夠,因為單憑
baber_chair 無法保證一名顧客離開理發椅之前,另一位顧客不會坐到該理發椅上,
因此增加信號量leave_barberchair,讓顧客離開理發椅後,釋放該信號,而理發
師接收到該信號後才釋放barber_chair 等待下一位顧客。
c) 在理發的過程中,需要保證是自己理發完畢,才能夠進行下面的付款、離開理發椅的活
動。這個機制是通過customer 進程獲得給他理發的理發師編號來實現的,這樣,當
該編號的理發師釋放對應的finished[i]信號的時候,該顧客才理發完畢。
d) 理發師是通過mutex 信號量保證他們每個人同時只進行一項操作(理發或者收款)。
e) 為了保證該顧客理發完畢後馬上可以付款離開,就應該保證給該顧客理發的理發師在理
發完畢後馬上到收銀台進入收款操作而不是給下一位顧客服務。在偽碼中由以下機制實
現:即顧客在釋放離開理發椅的信號前,發出付款的信號。這樣該理發師得不到顧客的
離開理發椅的信號,不能進入下一個循環為下一名顧客服務,而只能進入收款台的收款
操作。直到顧客接到收據後,才釋放離開理發椅的信號,離開理發椅,讓理發師釋放該
理發椅的信號,讓下一位等待的顧客坐到理發椅上。
(2)barber 進程
首先將該理發師的編號壓入隊列,供顧客提取。等待顧客坐到理發椅坐好(信號量
customer_ready),開始理發,理發結束後釋放結束信號(finished[i])。等待顧客
離開理發椅(leave_barberchair)(期間去收銀台進行收款活動),釋放理發椅空閑信
號(barber_chair),等待下一位顧客坐上來。
(3)cash(收銀台)進程
等待顧客付款(payment),執行收款操作,收款操作結束,給付收據(receipt)。
信號量總表:
信號量 wait signal
stand_capacity 顧客等待進入理發店 顧客離開站席區
sofa 顧客等待坐到沙發 顧客離開沙發
barber_chair 顧客等待空理發椅 理發師釋放空理發椅
customer_ready 理發師等待,直到一個顧客坐
到理發椅
顧客坐到理發椅上,給理發師
發出信號
mutex 等待理發師空閑,執行理發或
收款操作
理發師執行理發或收款結束,
進入空閑狀態
mutex1 執行入隊或出隊等待 入隊或出隊結束,釋放信號
finished[i] 顧客等待對應編號理發師理
發結束
理發師理發結束,釋放信號
leave_barberchair 理發師等待顧客離開理發椅 顧客付款完畢得到收據,離開
理發椅釋放信號
payment 收銀員等待顧客付款 顧客付款,發出信號
receipt 顧客等待收銀員收、開具收據收銀員收款結束、開具收據,
釋放信號
偽碼:
semaphore stand_capacity=5;
semaphore sofa=4;
semaphore barber_chair=3;
semaphore customer_ready=0;
semaphore mutex=3;
semaphore mutex1=1;
semaphore finished[3]={0,0,0};
semaphore leave_barberchair=0;
semaphore payment=0;
semaphore receipt=0;
void customer()
{
int barber_number;
wait(stand_capacity); //等待進入理發店
enter_room(); //進入理發店
wait(sofa); //等待沙發
leave_stand_section(); //離開站席區
signal(stand_capacity);
sit_on_sofa(); //坐在沙發上
wait(barber_chair); //等待理發椅
get_up_sofa(); //離開沙發
signal(sofa);
wait(mutex1);
sit_on_barberchair(); //坐到理發椅上
signal(customer_ready);
barber_number=dequeue(); //得到理發師編號
signal(mutex1);
wait(finished[barber_number]); //等待理發結束
pay(); //付款
signal(payment); //付款
wait(receipt); //等待收據
get_up_barberchair(); //離開理發椅
signal(leave_barberchair); //發出離開理發椅信號
exit_shop(); //了離開理發店
}
void barber(int i)
{
while(true)
{
wait(mutex1);
enqueue(i); //將該理發師的編號加入隊列
signal(mutex1);
wait(customer_ready); //等待顧客准備好
wait(mutex);
cut_hair(); //理發
signal(mutex);
signal(finished[i]); //理發結束
wait(leave_barberchair); //等待顧客離開理發椅信號
signal(barber_chair); //釋放barber_chair 信號
}
}
void cash() //收銀
{
while(true)
{
wait(payment); //等待顧客付款
wait(mutex); //原子操作
get_pay(); //接受付款
give_receipt(); //給顧客收據
signal(mutex);
signal(receipt); //收銀完畢,釋放信號
}
}
分析:
在分析該問題過程中,出現若干問題,是參閱相關資料後才認識到這些問題的隱蔽性和嚴重
性的,主要包括:
(1)在顧客進程,如果是在釋放leave_barberchair 信號之後進行付款動作的話,很
容易造成沒有收銀員為其收款的情形, 原因是: 為該顧客理發的理發師收到
leave_barberchair 信號後,釋放barber_chair 信號,另外一名顧客坐到理發椅上,
該理發師有可能為這另外一名顧客理發,而沒有為剛理完發的顧客收款。為解決這個問題,
就是採取在釋放leave_barberchair 信號之前,完成付款操作。這樣該理發師無法進入
下一輪循環為另外顧客服務,只能到收銀台收款。
(2)本演算法是通過給理發師編號的方式,當顧客坐到某理發椅上也同時獲得理發師的編號,
如此,當該理發師理發結束,釋放信號,顧客只有接收到為其理發的理發師的理發結束信號
才會進行付款等操作。這樣實現,是為避免這樣的錯誤,即:如果僅用一個finished 信
號量的話,很容易出現別的理發師理發完畢釋放了finished 信號,把正在理發的這位顧
客趕去付款,而已經理完發的顧客卻被阻塞在理發椅上的情形。當然也可以為顧客進行編
號,讓理發師獲取他理發的顧客的編號,但這樣就會限制顧客的數量,因為finished[]
數組不能是無限的。而為理發師編號,則只需要三個元素即可。
3.參考文獻:
左金平 計算機操作系統中哲學家進餐問題探究。
參考教材 操作系統—內核與設計原理
其他網路資源

⑧ 如何編程使「哲學家就餐問題」產生死鎖

不懂。......

⑨ 哲學家進餐問題的演算法與實現

1.哲學家進餐問題:
(1) 在什麼情況下5 個哲學家全部吃不上飯考慮兩種實現的方式,如下:
A. 演算法描述: void philosopher(int i) /*i:哲學家編號,從0 到4*/ {while (TRUE) { think( ); /*哲學家正在思考*/ take_fork(i); /*取左側的筷子*/ take_fork((i+1) % N); /*取左側筷子;%為取模運算*/eat( ); /*吃飯*/put_fork(i); /*把左側筷子放回桌子*/ put_fork((i+1) % N); /*把右側筷子放回桌子*/ } } 分析:假如所有的哲學家都同時拿起左側筷子,看到右側筷子不可用,又都放下左側筷子,等一會兒,又同時拿起左側筷子,如此這般,永遠重復。對於這種情況,即所有的程序都在無限期地運行,但是都無法取得任何進展,即出現飢餓,所有哲學家都吃不上飯。
B.演算法描述:規定在拿到左側的筷子後,先檢查右面的筷子是否可用。如果不可用,則先放下左側筷子,等一段時間再重復整個過程。分析:當出現以下情形,在某一個瞬間,所有的哲學家都同時啟動這個演算法,拿起左側的筷子,而看到右側筷子不可用,又都放下左側筷子,等一會兒,又同時拿起左側筷子……如此這樣永遠重復下去。對於這種情況,所有的程序都在運行,但卻無法取得進展,即出現飢餓,所有的哲學家都吃不上飯。
(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 ; semaphorechopstick[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]); } }
C.原理:規定奇數號的哲學家先拿起他左邊的筷子,然後再去拿他右邊的筷子;而偶數號的哲學家則相反.按此規定,將是1,2號哲學家競爭1號筷子,3,4號哲學家競爭3號筷子.即五個哲學家都競爭奇數號筷子,獲得後,再去競爭偶數號筷子,最後總會有一個哲學家能獲得兩支筷子而進餐。而申請不到的哲學家進入阻塞等待隊列,根FIFO原則,則先申請的哲學家會較先可以吃飯,因此不會出現餓死的哲學家。
偽碼: semaphore chopstick[5]={1,1,1,1,1}; void philosopher(int i) { while(true) { think(); if(i%2== 0) //偶數哲學家,先右後左。 { wait (chopstick[ i + 1 ] mod 5) ; wait (chopstick[ i]) ;eat(); signal (chopstick[ i + 1 ] mod 5) ; signal (chopstick[ i]) ; } Else //奇數哲學家,先左後右。 { wait (chopstick[ i]) ; wait (chopstick[ i +1 ] mod 5) ; eat(); signal (chopstick[ i]) ; signal (chopstick[ i + 1 ] mod 5); } }
D.利用管程機制實現(最終該實現是失敗的,見以下分析):原理:不是對每隻筷子設置信號量,而是對每個哲學家設置信號量。test()函數有以下作用:
a. 如果當前處理的哲學家處於飢餓狀態且兩側哲學家不在吃飯狀態,則當前哲學家通過 test()函數試圖進入吃飯狀態。
b. 如果通過test()進入吃飯狀態不成功,那麼當前哲學家就在該信號量阻塞等待,直到其他的哲學家進程通過test()將該哲學家的狀態設置為EATING。
c. 當一個哲學家進程調用put_forks()放下筷子的時候,會通過test()測試它的鄰居,如果鄰居處於飢餓狀態,且該鄰居的鄰居不在吃飯狀態,則該鄰居進入吃飯狀態。由上所述,該演算法不會出現死鎖,因為一個哲學家只有在兩個鄰座都不在進餐時,才允許轉換到進餐狀態。該演算法會出現某個哲學家適終無法吃飯的情況,即當該哲學家的左右兩個哲學家交替處在吃飯的狀態的時候,則該哲學家始終無法進入吃飯的狀態,因此不滿足題目的要求。但是該演算法能夠實現對於任意多位哲學家的情況都能獲得最大的並行度,因此具有重要的意義。
偽碼:#define N 5 /* 哲學家人數*/#define LEFT (i-1+N)%N /* i的左鄰號碼 */ #define RIGHT (i+1)%N /* i的右鄰號碼 */ typedef enum { THINKING, HUNGRY, EATING } phil_state; /*哲學家狀態*/ monitor dp /*管程*/ { phil_state state[N]; semaphore mutex =1; semaphore s[N];/*每個哲學家一個信號量,初始值為0*/void test(int i) { if ( state[i] == HUNGRY &&state[LEFT(i)] != EATING&& state[RIGHT(i)] != EATING ) { state[i] = EATING; V(s[i]); } } void get_forks(inti) { P(mutex); state[i] = HUNGRY; test(i); /*試圖得到兩支筷子*/ V(mutex); P(s[i]); /*得不到筷子則阻塞*/ } void put_forks(int i) { P(mutex); state[i]= THINKING;test(LEFT(i)); /*看左鄰是否進餐*/ test(RIGHT(i)); /*看右鄰是否進餐*/ V(mutex); } } 哲學家進程如下: void philosopher(int process) { while(true) { think();get_forks(process); eat(); put_forks(process); } }
2.理發師問題:一個理發店有一個入口和一個出口。理發店內有一個可站5 位顧客的站席區、4 個單人沙發、3 個理發師及其專用理發工具、一個收銀台。新來的顧客坐在沙發上等待;沒有空沙發時,可在站席區等待;站席區滿時,只能在入口外等待。理發師可從事理發、收銀和休息三種活動。
理發店的活動滿足下列條件:
1)休息的理發師是坐地自己專用的理發椅上,不會佔用顧客的沙發;
2)處理休息狀態的理發師可為在沙發上等待時間最長的顧客理發;
3)理發時間長短由理發師決定;
4)在站席區等待時間最長的顧客可坐到空閑的理發上;
5)任何時刻最多隻能有一個理發師在收銀。試用信號量機制或管程機制實現理發師進程和顧客進程。
原理:
(1) customer 進程:首先檢查站席區是否已滿(stand_capacity),若滿選擇離開,否則進入站席區,即進入理發店。在站席區等待沙發的空位(信號量sofa),如果沙發已滿,則進入阻塞等待隊列,直到出現空位,在站席區中等待時間最長的顧客離開站席區(stand_capacity)。坐到沙發上,等待理發椅(barber_chair),如果理發椅已滿,則進入阻塞等待隊列,直到出現空位,在沙發上等待時間最長的顧客離開沙發(釋放信號量sofa)。坐到理發椅上,釋放准備好的信號(customer_ready),獲得該理發師的編號(0~1 的數字)。等待理發師理發結束(finished[barber_number])。在離開理發椅之前付款(payment),等待收據 (receipt),離開理發椅(leave_barberchair)。最後離開理發店。
這里需要注意幾點:
a) 首先是幾個需要進行互斥處理的地方,主要包括:進入站席區、進入沙發、進入理發椅和付款幾個地方。
b) 通過barber_chair保證一個理發椅上最多隻有一名顧客。但這也不夠,因為單憑 baber_chair 無法保證一名顧客離開理發椅之前,另一位顧客不會坐到該理發椅上,因此增加信號量leave_barberchair,讓顧客離開理發椅後,釋放該信號,而理發師接收到該信號後才釋放barber_chair 等待下一位顧客。
c) 在理發的過程中,需要保證是自己理發完畢,才能夠進行下面的付款、離開理發椅的活動。這個機制是通過customer 進程獲得給他理發的理發師編號來實現的,這樣,當該編號的理發師釋放對應的finished[i]信號的時候,該顧客才理發完畢。
d) 理發師是通過mutex 信號量保證他們每個人同時只進行一項操作(理發或者收款)。
e) 為了保證該顧客理發完畢後馬上可以付款離開,就應該保證給該顧客理發的理發師在理發完畢後馬上到收銀台進入收款操作而不是給下一位顧客服務。在偽碼中由以下機制實現:即顧客在釋放離開理發椅的信號前,發出付款的信號。這樣該理發師得不到顧客的離開理發椅的信號,不能進入下一個循環為下一名顧客服務,而只能進入收款台的收款操作。直到顧客接到收據後,才釋放離開理發椅的信號,離開理發椅,讓理發師釋放該理發椅的信號,讓下一位等待的顧客坐到理發椅上。
(2)barber 進程首先將該理發師的編號壓入隊列,供顧客提取。等待顧客坐到理發椅坐好(信號量 customer_ready),開始理發,理發結束後釋放結束信號(finished[i])。等待顧客離開理發椅(leave_barberchair)(期間去收銀台進行收款活動),釋放理發椅空閑信號(barber_chair),等待下一位顧客坐上來。
(3)cash(收銀台)進程等待顧客付款(payment),執行收款操作,收款操作結束,給付收據(receipt)。信號量總表:信號量 waitsignal stand_capacity 顧客等待進入理發店顧客離開站席區 sofa 顧客等待坐到沙發顧客離開沙發 barber_chair 顧客等待空理發椅理發師釋放空理發椅 customer_ready 理發師等待,直到一個顧客坐到理發椅顧客坐到理發椅上,給理發師發出信號 mutex 等待理發師空閑,執行理發或收款操作理發師執行理發或收款結束,進入空閑狀態 mutex1執行入隊或出隊等待入隊或出隊結束,釋放信號 finished[i] 顧客等待對應編號理發師理發結束理發師理發結束,釋放信號 leave_barberchair 理發師等待顧客離開理發椅顧客付款完畢得到收據,離開理發椅釋放信號 payment 收銀員等待顧客付款顧客付款,發出信號 receipt 顧客等待收銀員收、開具收據收銀員收款結束、開具收據,釋放信號
偽碼: semaphore stand_capacity=5; semaphore sofa=4; semaphorebarber_chair=3; semaphore customer_ready=0; semaphore mutex=3; semaphoremutex1=1; semaphore finished[3]={0,0,0}; semaphore leave_barberchair=0;semaphore payment=0; semaphore receipt=0; void customer() { int barber_number;wait(stand_capacity); //等待進入理發店 enter_room(); //進入理發店 wait(sofa); //等待沙發 leave_stand_section(); //離開站席區 signal(stand_capacity); sit_on_sofa(); //坐在沙發上 wait(barber_chair); //等待理發椅 get_up_sofa(); //離開沙發 signal(sofa); wait(mutex1);sit_on_barberchair(); //坐到理發椅上 signal(customer_ready); barber_number=dequeue(); //得到理發師編號 signal(mutex1); wait(finished[barber_number]);//等待理發結束 pay(); //付款 signal(payment); //付款 wait(receipt); //等待收據 get_up_barberchair(); //離開理發椅 signal(leave_barberchair); //發出離開理發椅信號 exit_shop(); //了離開理發店 } void barber(int i) { while(true) { wait(mutex1);enqueue(i); //將該理發師的編號加入隊列 signal(mutex1); wait(customer_ready); //等待顧客准備好 wait(mutex); cut_hair(); //理發 signal(mutex); signal(finished[i]); //理發結束 wait(leave_barberchair); //等待顧客離開理發椅信號 signal(barber_chair); //釋放barber_chair 信號 } } void cash() //收銀 { while(true) { wait(payment); //等待顧客付款 wait(mutex); //原子操作 get_pay(); //接受付款 give_receipt(); //給顧客收據 signal(mutex); signal(receipt); //收銀完畢,釋放信號 } }
分析:在分析該問題過程中,出現若干問題,是參閱相關資料後才認識到這些問題的隱蔽性和嚴重性的,主要包括:
(1)在顧客進程,如果是在釋放leave_barberchair 信號之後進行付款動作的話,很容易造成沒有收銀員為其收款的情形,原因是:為該顧客理發的理發師收到 leave_barberchair 信號後,釋放barber_chair 信號,另外一名顧客坐到理發椅上,該理發師有可能為這另外一名顧客理發,而沒有為剛理完發的顧客收款。為解決這個問題,就是採取在釋放leave_barberchair 信號之前,完成付款操作。這樣該理發師無法進入下一輪循環為另外顧客服務,只能到收銀台收款。
(2)本演算法是通過給理發師編號的方式,當顧客坐到某理發椅上也同時獲得理發師的編號,如此,當該理發師理發結束,釋放信號,顧客只有接收到為其理發的理發師的理發結束信號才會進行付款等操作。這樣實現,是為避免這樣的錯誤,即:如果僅用一個finished 信號量的話,很容易出現別的理發師理發完畢釋放了finished 信號,把正在理發的這位顧客趕去付款,而已經理完發的顧客卻被阻塞在理發椅上的情形。當然也可以為顧客進行編號,讓理發師獲取他理發的顧客的編號,但這樣就會限制顧客的數量,因為finished[] 數組不能是無限的。而為理發師編號,則只需要三個元素即可。

⑩ 用java多線程編寫哲學家就餐程序 利用多線程技術編寫哲學家就餐程序,使之在運行時能演示產生死鎖的情況,

代碼自己寫!

閱讀全文

與哲學家就餐java相關的資料

熱點內容
戰地什麼伺服器 瀏覽:297
安卓為什麼老是閃退怎麼辦 瀏覽:801
樂高機器人的編程軟體下載 瀏覽:223
工作中怎麼使用加密狗 瀏覽:735
雲伺服器的後台找不到 瀏覽:98
php逐行寫入文件 瀏覽:912
javaoracleweb 瀏覽:440
京東加密碼怎麼弄 瀏覽:467
單片機程序員培訓 瀏覽:992
PHP商城源代碼csdn 瀏覽:636
怎麼把電腦里文件夾挪出來 瀏覽:693
java流程處理 瀏覽:685
ftp創建本地文件夾 瀏覽:660
腰椎第一節壓縮 瀏覽:738
xp去掉加密屬性 瀏覽:117
2345怎麼壓縮文件 瀏覽:982
迷你奪寶新演算法 瀏覽:407
伺服器如何防止木馬控制 瀏覽:715
壓縮空氣用電磁閥 瀏覽:742
微信為什麼不能設置加密認證 瀏覽:672