Question

J'essaie d'apprendre le principe de base d'un sémaphore dans le problème de Dining Philosopher. À l'heure actuelle, j'ai un tableau de baguettes de classe et chaque baguette a un sémaphore avec 1 autorisation disponible:

public class Chopstick
{
    Thread holder = null;
    private Semaphore lock = new Semaphore(1);

    public synchronized void take() throws InterruptedException
    {
        this.lock.acquire();
        holder = Thread.currentThread();

    }

    public synchronized void release()
    {   
        this.lock.release();
        holder = null;
    }
}

La variable titulaire est utilisée pour une fonction dont je ne suis pas sûr d'avoir besoin:

public synchronized void conditionalRelease()
{
    if (holder == Thread.currentThread())
    {
        holder = null;
        this.lock.release();
    }
}

Le programme compile et exécute, mais semble avoir du mal à libérer les baguettes. Parfois, les baguettes sont libérées, parfois non. Quand ils ne libèrent pas, le programme se bloque lorsque toutes les baguettes sont prises et qu'un philosophe a faim.

Voici le code de la classe Philosopher permettant de libérer la baguette après un laps de temps aléatoire:

System.out.println(this.name + " is eating");
Thread.sleep(this.getRandTime());
System.out.println(this.name + " has finished eating");

rightChopstick.release();
System.out.println(this.name + " has released the right chopstick");
leftChopstick.release();
System.out.println(this.name + " has released the left chopstick");

Mon programme génère "Le philosophe 0 a fini de manger", par exemple, et continue l'exécution. Les deux autres lignes ne sont jamais affichées. Il est donc évident que quelque chose ne va pas avec la façon dont je publie.

Toute aide est appréciée.

Était-ce utile?

La solution

Je prendrais le mot clé "synchronisé" dans les signatures de votre méthode. Vous utilisez un mécanisme de verrouillage externe (le sémaphore, dans ce cas). Le mot clé 'synchronized' tente d'obtenir des verrous en utilisant le propre mutex de l'objet. Vous verrouillez maintenant deux ressources qui, à mon avis, pourraient provoquer une impasse.

Autres conseils

Le problème est que lorsque thread1 a une baguette spécifique et qu'une autre essaye d'obtenir le même, elle attendra dans la méthode take () de la ligne this.lock.acquire () ; mais il NE ne libèrera pas le moniteur sur l'objet lui-même.

Si maintenant thread1 tente de libérer la baguette, il ne peut pas entrer la méthode release () car elle est toujours verrouillée par l'autre thread en attente dans take () . C'est une impasse

Il semble un peu déroutant de constater que vous tenez à la fois une baguette et un sémaphore de taille 1. En général, un sémaphore fournit des tickets à une ressource et si vous n’avez qu’un ticket, il s’agit d’une exclusion mutuelle identique à un verrou (un bloc synchronisé ou un objet verrouillé). Vous pourriez envisager de transformer le baguette en objet de verrouillage lui-même.

J’ai déjà publié un article sur les philosophes de la restauration à Java, si cela vous intéresse, même s’il s’agit vraiment d’éviter une impasse en utilisant d’autres stratégies.

Assurez-vous qu'aucun mot clé de verrouillage ou synchronisé n'est utilisé. Le code ci-dessous pour le bâtonnet fonctionne bien pour moi. Ce n’est pas un professionnel, mais vous devez en donner une idée;

public class Chopstick {
private boolean inuse;
Semaphore sem;

public Chopstick(){

    inuse = false;
    sem = new Semaphore(1);
}
public void pickUp()
{
    try
    {
        while(inuse)
        {
            try
            {
                sem.acquire();

            }
            catch(InterruptedException e) {}
        }
        inuse = true;
    }catch(Exception e){}
}
public void putDown()
{
    try
    {
        inuse = false;
        sem.release();

    }
    catch (Exception e){}
}

}

Philospher doit avoir le verrou sur les deux bâtonnets avant de commencer à manger. Les méthodes suivantes le feront fonctionner:

public synchronized void startEating() {
    leftChopstick.acquire();
    rightChopstick.acquire();
}

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top