7

Java セマフォを使用してこの問題を解決する必要がありますが、方法がわかりませんし、関連する Java 資料も見つかりません。これはそれがどのようになるかです:

スレッドには、男性と女性の種類があります。どちらも、BATHROOM_SIZE の同じリソースを使用したいと考えています。5 つのルール:

  1. すべてのスレッドは、リソースを使用する必要があることを通知した後、それを使用できるようになるまで待機する必要があります。
  2. BATHOOM_SIZE を超えるスレッドが同時にリソースを使用している状況を回避します。
  3. 女性と男性が同時にバスルームを使用するのを防ぎます。
  4. スレッドは同時にリソースを使用する必要があります。1 つのタイプのスレッドが多数ある場合、最大 BATHROOM_SIZE のスレッドがリソースを使用する必要があります。
  5. 飢餓を防ぎます。

結果

対象:

女性1名、男性1名、女性5名、男性5名

失敗:

5女1男、5男1女、2男2女、5男5女。

私は月曜日からそれを機能させようとしてきましたが、今ではアイデアが尽きてしまいました。

コード

したがって、私の仕事は、BathroomInterface を実装する Bathroom.java クラスを作成することです。

public interface BathroomInterface {

    public static final int BATHROOM_SIZE = 3; //3 is just example
    void manEnter();
    void manExit();
    void womanEnter();
    void womanExit();
}

システムには、次のように機能する多数の男性スレッドと女性スレッドがあります。

for(int i = 0; i < n; i++) {
  bathroom.manEnter();
  //uses bathroom random amount of time
  bathroom.manExit();
}

for(int i = 0; i < m; i++) {
  bathroom.womanEnter();
  //uses bathroom random amount of time
  bathroom.womanExit();
}

また、 Bathroom.javaクラスのスキームもあります。拡張する必要があります。

import java.util.concurrent.Semaphore;

public class Bathroom implements BathroomInterface {

    
    private Semaphore mutex = new Semaphore(1, true);

    public void womanEnter() {
        mutex.acquireUninterruptibly();
    }

    public void womanExit() {
        mutex.release();
    }

    public void manEnter() {
        mutex.acquireUninterruptibly();        
    }

    public void manExit() {
        mutex.release();
    }
}

これは私がこれまでに作ったものです:

import java.util.concurrent.Semaphore;

public class Bathroom implements BathroomInterface {
    int manW=0, manU=0, womanW=0, womanU=0; //*U-using, *W-waiting
    private Semaphore mutex = new Semaphore(1, false);

    public void womanEnter() {
        womanW++;
        StateChange();
    }

    public void womanExit() {
        womanU--;
        mutex.release();
        StateChange();
    }

    public void manEnter(){
        manW++;
        StateChange();
    }

    public void manExit() {
        manU--;
        mutex.release();
        StateChange();
    }
    
    void StateChange() {
        if(womanU==0 && manU==0) {
            if(manW>womanW) {
                while(manW>0 && manU<BATHROOM_SIZE) {
                    manW--;
                    manU++;
                    mutex.acquireUninterruptibly();
                }
            }
            else {
                while(womanW>0 && womanU<BATHROOM_SIZE) {
                    womanW--;
                    womanU++;
                    mutex.acquireUninterruptibly();
                }
            }
        }
        if(womanU==0 && manU<BATHROOM_SIZE) {
            while(manW>0 && manU<BATHROOM_SIZE) {
                manW--;
                manU++;
                mutex.acquireUninterruptibly();
            }
        }
        if(manU==0 && womanU<BATHROOM_SIZE) {
            while(womanW>0 && womanU<BATHROOM_SIZE) {
                womanW--;
                womanU++;
                mutex.acquireUninterruptibly();
            }
        }
    }
}
4

4 に答える 4

6

実際、この演習はセマフォではなくモニターを使用して行われます。あなたがしていることはほとんど問題ありません。条件がありません。したがって、バスルーム クラスで次のように宣言します。

ロック:

private Lock lock = new ReentrantLock();

ロックにアタッチされた 2 つの条件またはキュー:

private Condition womenWaitingQueue = lock.newCondition();
private Condition menWaitingQueue = lock.newCondition();

待機中の数を知るための 2 つのカウンターと、使用中の数を知るための 2 つのカウンター:

private int womenWaitingN = 0;
private int menWaitingN = 0;
private int womenUsingN = 0;
private int menUsingN = 0;

そしてもちろん、リソースの数:

private final int BATHROOM_CAPACITY = 5;
private int free_resources = BATHROOM_CAPACITY;

4つの機能はすべてここにありましたが、宿題タグのために削除されました

ここで重要なことは、待っている女性がいる場合は男性をトイレに入れないようにすることで、空腹を防ぐことです。

そのため、条件として、男性がトイレに行きたい場合、トイレに少なくとも 1 つの空きスポットがあるかどうか (無料のリソースを使用) と、トイレに女性がいるかどうか (womenUsingN を使用) を確認する必要があります。これら 2 つの条件のいずれかが満たされない場合、男性は (menWaitingQueue を使用して) 待機する必要があります。

menWaitingQueue.await();

男性がトイレを出るとき、待っている女性がいるかどうかを確認する必要があります (womenWaitingN)。

womanWaitingQueue.signal();

menUsingN カウンターがあるため、これによって合図された女性は、トイレに男性がいなくなるまで入ることができません。待っている女性がいない場合は、男性にトイレに入る合図を出すことができます。これにより、(待っている場合)異性が優先されるため、飢餓を防ぐことができます。

最後に、すべての関数は、各開始/終了関数の開始/終了時にロックをロック/ロック解除する必要があります。

lock.lock();
lock.unlock();

この新しい情報により、機能を自分で作成できるようになると思います。幸運を!

于 2012-06-21T13:23:26.733 に答える
2

特にミューテックスが実際に保護することになっているものと、mutex.acquireおよびmutex.releaseのセマンティクス全体に苦労していると思います。これにアプローチする方法についてのヒントを与えるために、問題を少し単純化してみましょう。

単純なセマフォよりも複雑な、2 つのクライアント クラスと枯渇防止を備えた同時実行オブジェクトを実装するよう求められます。私はあなたのためにそれをするつもりはありませんが、Java6 より前の時代に単純なセマフォがどのように見えたかを示すつもりです:

public class Resource {

    private int numClients = 0;
    private final int maxClients;

    public Resource(int maxClients) {
        this.maxClients = maxClients;
    }

    public synchronized void acquire() {
        while (!clientCanAcquire()) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        ++numClients;
        printState();
    }

    public synchronized void release() {
        --numClients;
        printState();
        notify();
    }

    private boolean clientCanAcquire() {
        return numClients < maxClients;
    }

    private void printState() {
        System.out.println("Resource is currently acquired by " + numClients
                + " clients");
    }
}

クライアントは次のようにこれにアクセスできます。

import java.util.Random;

public class Client implements Runnable {

    private Resource resource;
    private Random rnd = new Random();

    public Client(Resource resource) {
        this.resource = resource;
    }

    public void run() {
        try {
            Thread.sleep(rnd.nextInt(1000));
            resource.acquire();
            Thread.sleep(rnd.nextInt(1000));
            resource.release();
        } catch (InterruptedException e) {
        }
    }
}

そして、すべてを駆動できる最も単純なアプリケーションは次のようになります。

public class App {

    public static void main(String[] arg) {

        Resource r = new Resource(3);
        for (int i = 0; i < 10; i++) {
            Thread client = new Thread(new Client(r));
            client.start();
        }
    }
}

リソースは、クライアントがいつアクセスできるかを決定するために必要な情報を内部変数に格納します。マルチスレッド アプリケーションでは、これらの変数へのアクセスを同期する必要があります。これを行う最も簡単な方法を次に示しますが、次のように言うこともできます。

private Object mutex = new Object();

その後

synchronized (mutex) { }

または他のタイプのミューテックス。

問題は単純な通常のセマフォよりも複雑ですが、根底にあるロジックはかなり似ているはずです。

于 2012-06-21T14:24:05.527 に答える
0

http://se.inf.ethz.ch/courses/2013a_spring/ccc/に解決策があります。

あなたはいくつかの助けのためにそれを参照することができます.

于 2013-09-22T21:23:59.567 に答える
0

@Th0rndikeわかりました、私はあなたのヒントに従い、次のようにsthを書きました:

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.*;

public class Bathroom implements BathroomInterface {
    private Semaphore mutex = new Semaphore(1, false);

    private Lock lock = new ReentrantLock();
    private Condition womenWaitingQueue = lock.newCondition();
    private Condition menWaitingQueue = lock.newCondition();

    private int womenWaitingN = 0;
    private int menWaitingN = 0;
    private int womenUsingN = 0;
    private int menUsingN = 0;

    private int free_res = BATHROOM_SIZE;

    public void womanEnter() {
        lock.lock();
        if(free_res>0 && menUsingN==0) {
            womenUsingN++;
            free_res--;
            mutex.acquireUninterruptibly();
        }
        else
            try {
                womenWaitingQueue.await();
            }
        catch(Exception e) {
            System.out.println("E!");
        }
        lock.unlock();
    }

    public void womanExit() {
        lock.lock();
        womenUsingN--;
        free_res++;
        mutex.release();
        if(menWaitingN>0) {
            try {
                menWaitingQueue.signal();
            }
            catch(Exception e) {
                System.out.println("E!");
            }
        }
        lock.unlock();
    }

    public void manEnter() {
        lock.lock();
        menUsingN++;
        free_res--;
        if(free_res>0 && womenUsingN==0) {
            mutex.acquireUninterruptibly();
        }
        else
            try {
                menWaitingQueue.await();
            }
        catch(Exception e) {
            System.out.println("E!");
        }
        lock.unlock();    
    }

    public void manExit() {
        lock.lock();
        menUsingN--;
        free_res++;
        mutex.release();
        if(womenWaitingN>0) {
            try {
                womenWaitingQueue.signal();
            }
            catch(Exception e) {
                System.out.println("E!");
            }
        }
        lock.unlock();
    }
}

しかし、自動プログラムチェッカーに送信すると、1man と 1woman のテストではすべて問題ありませんが、残りの部分では「リアルタイム超過」エラーが返されます。lock.lock()/unlock() を削除すると、「リアルタイム超過」エラーが「不正解」に変わります。

于 2012-06-21T23:54:18.673 に答える