2014-11-23 85 views
0

我正在尋找一種方法來解決使用信號量的哲學家哲學問題,我很困擾我該怎麼去做。我已經在下面包含了我的代碼。餐飲哲學家使用信號燈

class ChopStick{ 
    private int count; 
    private boolean inuse; 
    Lock lock = new ReentrantLock(); 
    Condition notInUse = lock.newCondition(); 

    public ChopStick(){ 
     inuse = false; 
    } 

    public void pickUp(){ 
     lock.lock(); 
     try{ 
      while(inuse){ 
       try{ 
        notInUse.await(); 
       }catch(InterruptedException e){} 
      } 
      inuse = true; 
     }finally{lock.unlock();} 
    } 

    public void putDown(){ 
     lock.lock(); 
     try{ 
      inuse = false; 
      notInUse.signal(); 
     }finally{lock.unlock();} 
    } 
} 

class Philosopher extends Thread{ 
    Semaphore sem; 
    private ChopStick ch1,ch2; //chopsticks 
    private int phil; //philosopher id 

    public Philosopher(int p, ChopStick left, ChopStick right, Semaphore s){ 
     phil = p; 
     ch1 = left; 
     ch2 = right; 
     sem = s; 
    } 

    public void run() { 
     while(true){ 
      try { 
       sem.acquire(); 
      } catch (InterruptedException e) {} 
       think(phil); 
       //pickup chopsticks 
       ch1.pickUp(); 
       ch2.pickUp(); 
       eat(phil); 
       //putdown chopsticks 
       ch1.putDown(); 
       ch2.putDown(); 
       sem.release(); 
      } 
     } 

我在想,當一個哲學家拿起使用sem.acquire()一根筷子,然後當他們使用sem.release()完成,但我不知道這是否是正確的。是嗎?

編輯所以我已經實現了這一點。它似乎工作,但我不知道。

class ChopStick{ 
    private Semaphore sem; 
    public ChopStick(Semaphore s){ 
      sem = s; 
    } 

    public void pickUp(){ 
      try{ 
        sem.acquire(); 
      }catch(InterruptedException e){} 
    } 
    public void putDown(){ 
      sem.release(); 
    } 
+0

https://www.youtube.com/watch?v=M3CNoX8wetM – Anonymous 2014-11-23 01:37:02

+0

我知道它是如何工作的,我正在尋求使用信號量解決。 – Strobes 2014-11-23 02:01:59

+0

@Strobes新代碼可能會遇到死鎖,請參閱編輯我的答案,以防止出現這種情況 – 2014-11-23 15:28:23

回答

4

而不是將一個信號量上Philosopher,我建議把對Chopstick一個信號; Philosopher要求獲得左右筷子的信號量,並在完成時釋放筷子的信號量。這將取代Chopstick上的ReentrantLock

爲防止死鎖,您可以使用tryAcquire(int permits, long timeout, TimeUnit unit),以便Philosopher釋放其左筷子的信號量,如果在超時時間內未能獲得其右筷子的信號量;如果您使用隨機超時(例如100到500毫秒),則每個Philosopher最終都應該取得進展。

編輯:您的新Chopstick代碼運行死鎖的風險 - 所有的哲學家拿起筷子左邊,然後等待永遠爲他們的權利筷子是自由的。一個tryAcquire將允許哲學家釋放它的左筷子,如果它在超時後不能獲得它的右筷子,這將允許哲學家在左邊繼續。

class ChopStick{ 
    private static Random random = new Random(); 

    // initialize with one permit 
    private Semaphore sem = new Semaphore(1); 

    public boolean pickUp(){ 
    try { 
     // wait between 100 and 500 milliseconds 
     return sem.tryAcquire(1, random.nextInt(400) + 100, TimeUnit.MILLISECONDS); 
    } catch(InterruptedException e) { 
     return false; 
    } 
    } 

    public void putDown(){ 
    sem.release(); 
    } 
} 

class Philosopher extends Thread { 
    public void run() { 
    while(true){ 
     think(phil); 
     doEat(); 
    } 

    private void doEat() { 
    if(ch1.pickup()) { 
     if(ch2.pickup()) { 
     eat(phil); 
     ch1.release(); 
     ch2.release(); 
     else { 
     ch1.release(); 
     doEat(); 
     } 
    else { 
     doEat(); 
    } 
    } 
} 
+0

I會嘗試這個併發布結果,當我可以。 – Strobes 2014-11-23 10:37:47

+0

請參閱上面的編輯。 – Strobes 2014-11-23 13:49:50

+1

這是正確的。 'Semaphore'必須應用於共享資源。 '筷子'是共享的,而不是'哲學家'。請記住,問題是兩個'Philosopher'對象試圖訪問相同的資源; '筷子'。如果你把它留給每個「哲學家」來決定什麼時候可以拿到「筷子」,每個人都很可能會貪婪地拒絕訪問它(每個「哲人」都想繼續吃)。如果讓資源指定何時可以使用,則問題已解決。 – hfontanez 2014-11-23 15:46:28