2012-04-15 122 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); 
} 

睡眠保持队列过程形式压倒处理器的一个转移。将其设置为适当的检查。只有在房间打开空间或添加转换时,您才可以设置中断以拉取队列项目。通过这种方式,如果房间已满,不会浪费时间尝试进入,但每个人都将至少有一个镜头立即进入。

这会强制转换以获取队列信号量,然后才能获得房间信号量。设置无死锁的层次结构。如果房间已满,用户将永远不会离开队列,但不会导致系统死锁。