1. 程式人生 > >程序同步互斥——不死鎖哲學家問題

程序同步互斥——不死鎖哲學家問題

一、問題分析


二、概要設計

(1)利用程序併發執行原理,採用奇數號哲學家先拿左叉子,偶數號哲學家先拿右叉子的演算法解決哲學家就餐問題。

(2)利用java中Swing技術將哲學家就餐的活動過程用可檢視形化介面表示出來


三、程式碼實現:

Philosopher類

  /**
   * Philosopher類模擬哲學家的就餐活動過程
   * @author Administrator
   */
  public class Philosopher extends JLabel implements Runnable{
  	/**
  	 * 哲學家編號
  	 */
  	private int id = 0;
  	
  	/**
  	 * suspend = true 執行緒暫停
  	 */
  	private boolean suspend = false;
  
  	public Philosopher(int id, Semaphore leftFork, Semaphore rightFork, 
  		//哲學家初始化設計,統一設計哲學家的初始狀態為思考
  	}
  	
  	/**
  	 * 若suspend設定為false,繼續運行當前程序
  	 */
  	public void setSuspend(boolean suspend) {
  		//使用Object的notifyAll()方法來喚醒當前執行緒
  	}
  	
  	/**
  	 * 狀態轉為思考
  	 */
  	private void think() {
  //返回資訊給使用者,並將當前影象設為思考的影象。
  	}
  	
  	/**
  	 * 狀態轉為就餐
  	 */
  	private void eat() {
  //返回資訊給使用者,並將當前影象設為思考的影象。
  	}
  	
  	/**
  	 * 申請右叉子
  	 */
  	private void waitRightFork(){
  		//使用Semaphore.acquire()向計數訊號量獲得一個許可,來模擬申請右			//叉子.
  //返回相關狀態資訊給使用者
  	}
  	
  	/**
  	 * 申請左叉子
  	 */
  	private void waitLeftFork() throws InterruptedException {
  //使用Semaphore.acquire()向計數訊號量獲得一個許可,來模擬申請左	//叉子.
  //返回相關狀態資訊給使用者
  	}
  	
  	/**
  	 * 釋放所有叉子
  	 */
  	private void releaseFork() {
  //使用Semaphore.release() 釋放一個許可,將其返回給訊號量。來模	//擬釋放左右叉子.
  //返回相關狀態資訊給使用者
  	}
  	
  	/**
  	 * 判斷是否要暫停當前程序
  	 */
  	private void checkSuspend() {
  		//Object的wait()方法來暫停當前執行緒
  	}
  	
  	/**
  	 * 奇數號哲學家先拿左叉子,偶數號哲學家先拿右叉子
  	 */
  	public void run() {
  		try{
  			while(true) {
  				//設狀態為思考
  				if(id % 2 == 1) {
  					//奇數號哲學家先拿左叉子
  				}
  				else {
  					//偶數號哲學家先拿右叉子
  				}
  				//設狀態為吃東西
  				//釋放所有叉子
  			}
  		}
  	}
  	
  }

四、除錯分析

(1)除錯和設計過程中遇到的問題與解決

1) 問題:實現同步互斥時,只用了簡單的執行緒同步方法,無法實現互斥

  解決方法:使用java中Semaphore類來建立訊號量,並通過 Semaphore.acquire() 和Semaphore.release()來模擬叉子的釋放和申請

2) 問題:本程式為方便使用者觀看哲學家們就餐的過程,在程式中添加了一個控制 按鈕來控制程式的執行和暫停,但java中的Thread.stop()被認為執行緒不安全, 所以不能使用該方法來控制執行緒.

  解決方法:Object的wait()和notifyAll()方法。使用這兩個方法讓執行緒暫停,並且還能恢復,向哲學家類中新增一個標誌變數suspend方法,每個狀態發生改變時,檢查標誌變數suspend的值來決定是否要暫停當前執行緒,從而主程式可以通過改變哲學家類中的suspend的值,來控制是否暫停當前哲學家程序。

3) 問題:釋放叉子和改變叉子的顯示狀態問題,如果先釋放叉子,然後再改變叉子狀態就會出現以下問題。

 

雖然叉子的訊號量已被申請出去,但使用者看到的卻是叉子還存在的狀態。

解決方法:先顯示叉子,再釋放叉子的訊號量。

五、使用者使用說明

本程式利用程序併發執行的原理,設計合適的演算法來解決哲學家就餐問題,並把哲學家們的活動過程用文字和視覺化影象顯示出來。所以在程式中只用一個用來控制程式暫停和執行的可操作按鈕。

六、測試與執行結果

本程式為模擬哲學家就餐的活動過程,如下圖所示5位哲學家和5把叉子,哲學家們的初始狀態都為“思考”,在程式介面中,順時針方向為左,逆時針方向為右

 

每個哲學家有3個狀態:“思考”,“飢餓”和“吃麵”,每個哲學家程序通過訊號量來實現同步互斥。為了方便使用者觀看,使用

Tread.sleep()方法使“思考”和“吃麵”狀態至少進行3秒。