8

そのため、セマフォの使用に問題があります。4 つの部屋と何人かの訪問者がいるコードを書きます。各部屋には、収容できる訪問者の数に一定の上限があります。したがって、満員の部屋に入ると、wait() がトリガーされます。訪問者は、別の部屋に入る前に部屋を出てはならないため、常に部屋にいます。

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();
}

2 人がお互いの部屋に入ろうとすると、デッドロックが発生します。また、何らかの理由でplacesLeftカウントが正しく出ていません。

それで、私は何をすべきですか?

編集:

何か他のことで忙しかったので、質問を復活させます。部屋がいっぱいになるため、問題は発生しません。ロックは、room1 の person1 が room2 に入りたいと同時に、room2 の person2 が room1 に入りたいときに発生します。私が理解しているように、おそらく同期と関係がありますか?リリース前にスタックするため、リリースは呼び出されません。私が理解しているように、1 つの部屋の取得と解放を同時に呼び出すことはできません。したがって、基本的に、room1 のセマフォ リリースは、room2 と同じように、accuire が呼び出されると同時に呼び出すことはできませんか? 私は初心者のコーダーであり、同期はまだそれほど明確ではありません。いずれかから同期を削除しても機能しないようです (これもかなり間違っています)。

4

6 に答える 6

2

独自に実装する代わりに、Java 標準ライブラリに組み込まれているjava.util.concurrent.Semaphoreを使用するのはどうですか?

java.util.concurrentパッケージには、セマフォとそれが提供する他の多くの便利な同期メカニズムをカバーする優れたチュートリアルがあります

于 2012-04-15T23:36:18.977 に答える
1

ディペンデンシー グラフに循環があると、デッドロックが発生します。2 人がお互いの部屋に入ろうとするとき、これは明らかにサイクルであり、デッドロックは自然な結果です。

ただし、サイクルを別の方法で処理する必要があります。サイクルが発生すると、すべての人がサイクルに沿って移動します (3 人以上の人が部屋を交換する場合があります)。

したがって、最初にサイクルが形成されているかどうかを判断してから、訪問者の場所を変更する必要があります。

于 2012-04-16T03:32:08.250 に答える
0

「どうすればよいですか?」という質問に答えるために、デッドロックを検出した場合は、デッドロックした訪問者の1人をスペースのある部屋に移動します。次に、彼を本当に欲しい部屋に移動します。これにより、基本的に、以下のルールに違反することなくスワップが可能になります。

  1. 客室にはX人を超える訪問者を含めることはできません
  2. 訪問者は常に正確に1つの部屋にいます
  3. 一度に1人の訪問者だけが部屋を変更できます(これが問題の核心です)

そこには約無数のセマフォロック戦略があることを覚えておいてください...

于 2012-04-15T23:43:57.370 に答える
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()メソッドを呼び出すため、デッドロックを防ぐのは非常に困難です。別のスレッドが現在そのインスタンスでメソッドを実行している場合、 thenrelease()の呼び出しrelease()はブロックされます。acquire()その 2 番目のスレッドが最終的release()に最初のインスタンスを呼び出すと、デッドロックが発生します。

個々の Semaphore インスタンスでの同期を、 という名前の単一オブジェクトでの同期に置き換えましたLOCK。実行するスレッドがacquire()のモニターをロックしましたLOCKrelease()したがって、このスレッドはメソッドを呼び出してもブロックされません。したがって、release()メソッドは常に終了します。これにより、デッドロックが解決されます。

于 2012-12-28T15:28:14.433 に答える
0

デッドロックは通常、階層セマフォ システムによって解決されます。典型的なデッドロックは次のようになります

プロセスA

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

プロセスB

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

すべてのプロセスが B の前に A を選択するだけです。これはgetSemaphore、アサートを使用して階層を強制する関数を作成することで実現できます。

あなたの特定のケースでは、これは明らかに問題を解決しませんが、この考えから推定することができます。

移行キューを作成します。ユーザーが部屋を変更したい場合、関数は次のようになります。

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

「3200」はセマフォのタイムアウトです。セマフォをスクワイアした後にプロセスが中断された場合でも、システムはデッドロック状態になります。これにより、1 時間のタイムアウトが発生します。システムの安定性に基づいて、論理値 1 分 5 秒に設定できます。次に、非ブロッキング セマフォを使用して一度に 1 つの転送のみを許可するキュー プロセッサを用意します。

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);
}

スリープは、プロセッサを圧倒するキュー プロセス フォームを維持します。適切なチェックに設定してください。ルームにスペースが開いているか、トランジションが追加された場合にのみ、キュー アイテムを取得するように割り込みを設定することもできます。こうすれば、部屋が満員の場合、入ろうとして時間を無駄にすることはありませんが、全員が少なくとも 1 発はすぐに入ることができます。

これにより、トランジションは、ルーム セマフォを取得する前にキュー セマフォを取得するように強制されます。デッドロックのない階層を設定します。ルームが満員の場合、ユーザーがキューから離れることはありませんが、システムがデッドロックすることはありません。

于 2015-07-27T18:41:58.277 に答える
0

現在の訪問者のリストを に追加して、この部屋の占有者の 1 人が入室を待っている部屋から訪問者が来ている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-15T23:13:36.403 に答える