如何将共享变量与两个信号量同步?

How to synchronize shared variable with two Semaphores?

我有一个练习,我有一个盛宴,其中 N = 10 个人一次从锅里吃 1 份。锅有最大份量 M = 5。还有一个厨师在锅空时填充锅 servingsAvailable = 0。填充期间不能进食。我必须同步线程,只从 Pot class 更改方法 fill 和 getServings(这些方法一开始是空的)。

你能告诉我我在这段代码中做错了什么吗?总金额应为 1000,但总是更少。我实现了锅装满然后5个人吃,然后装满等的情况,但是吃的份数不一致。

人class

public class Person extends Thread { // Reprezentuje tubylca
    Pot pot;
    int servingsConsumed = 0;
    public Person(String name, Pot pot) {
        super(name);
        this.pot = pot;
    }
    @Override
    public void run() {
        try {
            for (int i = 0; i < 100; ++i) {
                pot.getServing(this.getName());
                ++servingsConsumed;
                Thread.yield();
            }
        } catch(InterruptedException e) {
            return ;
        }
    }
}

厨师class

public class Cook extends Thread { // Reprezentuje kucharza
    Pot pot;
    public Cook(Pot pot) {
        this.pot = pot;
        setDaemon(true);
    }
    @Override
    public void run() {
        try {
            while(!isInterrupted()) {
                pot.fill();
            }
        } catch(InterruptedException e) {
            return ;
        }
    }
}

Pot.class

import java.util.concurrent.Semaphore;

public class Pot {
    static final int M = 5; // Pojemność kotła
    private Semaphore emptyPot = new Semaphore(1);
    private Semaphore available = new Semaphore(0);
    private int servingsAvailable = 0;
    private int totalServedCount = 0;

    private synchronized void insertServings(int value) {
        servingsAvailable = value;
    }

    private synchronized int removeServing() {
        --servingsAvailable;
        ++totalServedCount;
        return servingsAvailable;
    }

    public int getTotalServedCount() {
        return totalServedCount;
    }

    public void getServing(String nameOfPerson) throws InterruptedException {
        available.acquire();
        if (servingsAvailable != 0) {
            removeServing();
            System.out.println(nameOfPerson + " ate 1 portion from pot");
        }
        available.release();
    }

    public void fill() throws InterruptedException {
        available.acquire();
        if (servingsAvailable == 0) {
            insertServings(M);
            System.out.println("Fill the pot with M = " + M);
        }
        available.release();
    }
}

盛宴class(主)

public class Feast {
    public static void main(String[] args) throws InterruptedException {
        Pot pot = new Pot();
        Cook cook = new Cook(pot);
        final int N = 10;
        Person[] people = new Person[N];
        for (int i = 0; i < people.length; ++i) {
            people[i] = new Person("Person " + i, pot);
        }
        cook.start();
        for (Thread t : people) {
            t.start();
        }
        for (Thread t : people) {
            t.join();
        }
        cook.interrupt();
        System.out.printf("Total served: %d.\n", pot.getTotalServedCount());
        for (Person p : people) {
            System.out.printf("[%s] Ate %d servings.\n", p.getName(), p.servingsConsumed);
        }
        System.out.println("Finishing simulation.");
    }
}

到目前为止我取得的结果:我认为它应该在这里显示 1000 而不是 245。

您将信号量用作简单的互斥量,调用者无法通过任何方式知道有多少服务可用。如果你想用信号通知锅的状态,你应该在食物被填满和消耗时更新它们:

public void getServing(String nameOfPerson) throws InterruptedException {
    // take a permit and keep it
    available.acquire();
    System.out.println(nameOfPerson + " ate 1 portion from pot");
    if (removeServing() == 0) {
        // release a refill permit to the Cook
        emptyPot.release();
    }
}

public void fill() throws InterruptedException {
    // wait till pot is empty
    emptyPot.acquire();
    insertServings(M);
    System.out.println("Fill the pot with M = " + M);
    // release a permit for each serving
    available.release(M);
}