信号灯死锁
所以我有一个使用信号量的问题。 写一个代码,其中有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错误)。
将当前访问者列表添加到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
代表给定的代码。
等待访问者列表是一种策略,但与解决方案似乎没有密切关系。 – 2012-04-15 23:20:14
您需要某种方式来检测房间R中的访客A是否正在等待进入房间S,而房间S中的访客B是否正在等待进入房间R. – 2012-04-15 23:22:43
嗯,不。根据OP,您的情况无法解决。访客必须在一个房间里;他们不能在途中。因此,如果两个房间满了,游客就不能在它们之间移动。但这真的不是他的问题 - 他只是有缺陷,认识。 – 2012-04-15 23:25:18
而是实现自己的,有关使用java.util.concurrent.Semaphore这是建立在Java标准库如何呢?
java.util.concurrent
包有一个很好的tutorial涵盖信号量和它提供的许多其他有用的同步机制。
要回答你的问题,“我应该怎么办?”,如果检测到死锁,动陷入僵局游客之一的任何房间,空间。然后将他移到他真正想要的房间。这基本上允许交换而不违反下面的任何规则。
- 间绝不能包含比X参观者更
- 一个观众总是在只有一个房间
- 只有一个观众可以改变房间在同一时间(这确实是问题的症结所在)
请记住,在那里有大约十亿个信号量锁定策略...
死亡发生在依赖关系图中存在循环时。当两个人试图进入对方的房间时,这显然是一个循环,僵局是一个自然结果。
但是,您希望以其他方式处理周期:当周期发生时,所有人都沿着周期移动(可能有超过2人交换房间)。
因此,您应该首先确定一个循环是否形成,然后更改访问者的位置。
试试这个:
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()
方法时未被阻止。方法将因此总是终止。这解决了僵局。
死锁通常通过分层信号量系统解决。典型的死锁看起来像
进程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);
}
睡眠保持队列过程形式压倒处理器的一个转移。将其设置为适当的检查。只有在房间打开空间或添加转换时,您才可以设置中断以拉取队列项目。通过这种方式,如果房间已满,不会浪费时间尝试进入,但每个人都将至少有一个镜头立即进入。
这会强制转换以获取队列信号量,然后才能获得房间信号量。设置无死锁的层次结构。如果房间已满,用户将永远不会离开队列,但不会导致系统死锁。
如果两个房间都已满,死锁是合乎逻辑的结果。 – 2012-04-15 23:02:39
您的“ 2012-04-15 23:18:31
如果允许两位访客交换房间,或者在这种情况下会导致首选结果僵局? – 2012-04-15 23:35:13