2012-04-15 121 views
8

所以我有一個使用信號量的問題。 寫一個代碼,其中有4個房間和一些訪客。每個房間都有一定數量的遊客可以容納的帽子。因此進入一個完整的房間會觸發等待()。 訪客在進入另一個房間之前不得離開房間,因此他們總是在一個房間裏。信號燈死鎖

public class Semaphore { 

    private int placesLeft; 

    public Semaphore(int placesInRoom) { 
    this.placesLeft = placesInRoom; 
    } 

    public synchronized void acquire(Visitor visitor) { 
    Semaphore sem = visitor.getRoom().getSemaphore(); 

    try { 
     while (placesLeft <= 0) { 
     this.wait(); 
    } 

    } catch (InterruptedException e) {} 

    sem.release(); 
    placesLeft--; 
} 

public synchronized void release() { 
    placesLeft++; 
    this.notifyAll(); 
} 

當兩個人試圖進入彼此的房間時出現死鎖。 也出於某種原因,placesLeft計數是不正確的。

那我該怎麼辦?

編輯:

一直忙於別的事情,恢復的問題。 這個問題並不是因爲房間滿了而發生的,當房間1中的人1想要進入房間2並且來自房間2的人2想要進入房間1時發生鎖定。據我瞭解,它可能與同步處理有關?它們在發佈之前會卡住,因此不會調用發佈。據我所知,一個房間的精確和發佈不能稱爲同一時間。所以基本上room1信號量的釋放不能稱爲cuz,同樣的時間被稱爲精靈,同樣的room2?我是新手編碼器,同步還不太清楚。 從一個或另一個刪除同步似乎沒有工作(也prolly錯誤)。

+5

如果兩個房間都已滿,死鎖是合乎邏輯的結果。 – 2012-04-15 23:02:39

+2

您的「<= 0」是錯誤的症狀。值不應該低於0.所以「==」應該做。你爲什麼把_room_變成acquire()? – 2012-04-15 23:18:31

+0

如果允許兩位訪客交換房間,或者在這種情況下會導致首選結果僵局? – 2012-04-15 23:35:13

回答

0

將當前訪問者列表添加到Room,以便您可以檢查acquire,以確定來訪者是否來自某個房間的其他人的房間正在等待進入。您還需要添加訪客等待輸入的房間Visitor

Room comingFrom = visitor.getRoom(); 
while (placesLeft <= 0) { 
    for (Visitor waiter : room.getVisitors()) { 
     if (waiter.getWaitingForRoom().equals(comingFrom) { 
      // swap the visitors without releasing/acquiring any semaphores and return 
     } 
    } 
    this.wait(); 
} 

我有點不確定的邏輯來檢查,如果訪問者正在等待輸入當前訪問者離開同一個房間。我無法分辨哪個房間room代表給定的代碼。

+0

等待訪問者列表是一種策略,但與解決方案似乎沒有密切關係。 – 2012-04-15 23:20:14

+0

您需要某種方式來檢測房間R中的訪客A是否正在等待進入房間S,而房間S中的訪客B是否正在等待進入房間R. – 2012-04-15 23:22:43

+1

嗯,不。根據OP,您的情況無法解決。訪客必須在一個房間裏;他們不能在途中。因此,如果兩個房間滿了,遊客就不能在它們之間移動。但這真的不是他的問題 - 他只是有缺陷,認識。 – 2012-04-15 23:25:18

2

而是實現自己的,有關使用java.util.concurrent.Semaphore這是建立在Java標準庫如何呢?

java.util.concurrent包有一個很好的tutorial涵蓋信號量和它提供的許多其他有用的同步機制。

0

要回答你的問題,「我應該怎麼辦?」,如果檢測到死鎖,動陷入僵局遊客之一的任何房間,空間。然後將他移到他真正想要的房間。這基本上允許交換而不違反下面的任何規則。

  1. 間絕不能包含比X參觀者更
  2. 一個觀衆總是在只有一個房間
  3. 只有一個觀衆可以改變房間在同一時間(這確實是問題的癥結所在)

請記住,在那裏有大約十億個信號量鎖定策略...

1

死亡發生在依賴關係圖中存在循環時。當兩個人試圖進入對方的房間時,這顯然是一個循環,僵局是一個自然結果。

但是,您希望以其他方式處理週期:當週期發生時,所有人都沿着週期移動(可能有超過2人交換房間)。

因此,您應該首先確定一個循環是否形成,然後更改訪問者的位置。

0

試試這個:

public class Semaphore { 
    private final static Object LOCK = new Object(); 
    private int placesLeft; 

    public Semaphore(int placesInRoom) { 
    this.placesLeft = placesInRoom; 
    } 

    public void acquire(Visitor visitor) { 
     synchronized (LOCK) { 
      Semaphore sem = visitor.getRoom().getSemaphore(); 

      try { 
       while (placesLeft <= 0) { 
        LOCK.wait(); 
       } 
      } catch (InterruptedException e) {} 

     sem.release(); 
     placesLeft--; 
    } 
} 

public void release() { 
    synchronized(LOCK) { 
     placesLeft++; 
     LOCK.notifyAll(); 
    } 
} 

對個人信號燈實例同步的舊代碼。防止死鎖非常困難,因爲一個實例的acquire()方法調用另一個實例的release()。如果另一個線程當前正在另一個實例上執行acquire()方法,則對release()的調用會阻塞。如果第二個線程在第一個實例上終於調用release(),那麼就會出現死鎖。

我通過在名爲LOCK的單個對象上進行同步來替換單個信號量實例上的同步。執行acquire()的線程已鎖定LOCK的監視器。因此,該線程在調用release()方法時未被阻止。方法將因此總是終止。這解決了僵局。

0

死鎖通常通過分層信號量系統解決。典型的死鎖看起來像

進程A

getSemaphore('A'); 
getSemaphore('B'); 

進程B

getSemaphore('B'); 
getSemaphore('A'); 

只是所有進程B.之前選擇這可以通過編寫getSemaphore功能執行層級來實現與斷言。

對於你的具體情況,這並不能很好地解決問題,但你可以從這個想法推斷出來。

創建遷移隊列。當用戶想要更換房間時,您的功能可能如下所示:

ChangeRoom(person, from, to) 
{ 
    getSemaphore('room_queue', 3200); 
    enqueue(room_queue, Object(person, from, to)); 
    releaseSemaphore('room_queue'); 
} 

「3200」是一個信號燈超時。如果一個進程在信號量駐留後中斷,它仍然會使系統死鎖。這給了1小時超時。根據您的系統穩定性,您可以將其設置爲1分5秒的邏輯值。 然後有一個隊列處理器,其僅允許在一個時間與一個非阻塞旗語

QueueProcessor() 
{ 
    getSemaphore('room_queue', 3200); 
    for (transition = dequeue(room_queue)) 
    { 
     if (getNonBlockingSemaphore(transition.to) 
     { 
      releaseSemaphore(transition.from); 
      getSemaphore(transition.to); 
     } 
     continue; 
    } 
    releaseSemaphore('room_queue'); 
    sleep(10); 
} 

睡眠保持隊列過程形式壓倒處理器的一個轉移。將其設置爲適當的檢查。只有在房間打開空間或添加轉換時,您纔可以設置中斷以拉取隊列項目。通過這種方式,如果房間已滿,不會浪費時間嘗試進入,但每個人都將至少有一個鏡頭立即進入。

這會強制轉換以獲取隊列信號量,然後才能獲得房間信號量。設置無死鎖的層次結構。如果房間已滿,用戶將永遠不會離開隊列,但不會導致系統死鎖。