2009-03-03 7 views
5

Ich versuche, die grundlegende jist eines Semaphor in der Dining Philosopher Problem zu lernen. Gerade jetzt, ich habe eine Reihe von Klasse Ess-Stäbchen, und jeder Chopstick hat eine Semaphore mit 1 verfügbar Erlaubnis:Semaphore Probleme in Java mit den Dining Philosophen

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

Der Halter Variable für eine Funktion verwendet wird, die ich bin nicht sicher, ich brauche:

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

Das Programm kompiliert und läuft, scheint aber Probleme mit der Freigabe der Essstäbchen zu haben. Manchmal werden die Essstäbchen freigegeben, manchmal nicht. Wenn sie nicht loslassen, hängt das Programm schließlich auf, wenn alle Essstäbchen genommen sind und ein Philosoph hungrig ist.

Hier ist der Code innerhalb der Tutor-Klasse der Ess-Stäbchen nach unbestimmter Zeit zu lösen:

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

Mein Programm funktioniert Ausgang „Tutor 0 hat Essen fertig“, zum Beispiel, und setzt die Ausführung. Die anderen beiden Zeilen geben niemals aus, also ist offensichtlich etwas nicht in Ordnung mit der Art, wie ich loslasse.

Jede Hilfe wird geschätzt.

Antwort

8

Ich würde das Schlüsselwort "synchronized" aus Ihren Methodensignaturen nehmen. Sie verwenden einen externen Sperrmechanismus (in diesem Fall den Semaphor). Das 'synchronisierte' Schlüsselwort versucht, Sperren unter Verwendung des eigenen Mutex des Objekts zu erhalten. Sie sperren jetzt 2 Ressourcen, die möglicherweise einen Deadlock verursachen.

+0

Ha! Das war genau das, was es war ... Ich musste diese zwei verschiedenen Wege für eine Aufgabe implementieren und habe Code für die erste Methode kopiert und vergessen, das synchronisierte Schlüsselwort zu entfernen. Netter Fund. –

1

Das Problem ist, dass, wenn thread1 ein bestimmtes Ess-Stäbchen hat und eine anderes versucht, das gleiche zu bekommen es this.lock.acquire(); in dem take() -Methode auf der Leitung warten, aber es wird nicht freigeben den Monitor auf dem Objekt selbst.

Wenn nun thread1 versucht, das Essstäbchen zu lösen, kann es nicht in die release() -Methode gelangen, da es immer noch von dem anderen Thread gesperrt ist, der in take() wartet. Das ist ein Deadlock

1

Es scheint ein wenig verwirrend, dass Sie beide auf dem Essstäbchen verriegeln und es ein Semaphor der Größe 1 halten. Im Allgemeinen bietet ein Semaphor Tickets für eine Ressource, und wenn Sie nur ein Ticket haben, ist das effektiv gegenseitigen Ausschluss Das ist identisch mit einer Sperre (entweder ein synchronisierter Block oder ein Lock-Objekt). Sie könnten erwägen, das Essstäbchen tatsächlich zum Verschlussobjekt zu machen.

Ich habe vor einiger Zeit einen Blogpost über die Dining Philosophen in Java geschrieben, wenn es dich interessiert, obwohl es wirklich darum geht, Deadlock durch andere Strategien zu vermeiden.

+0

Sieht so aus, als ob dies Teil einer Hausaufgabe wäre, wo er eine Cooky-Anforderung hatte, die besagte, dass er Semaphoren verwenden musste. –

+0

Die andere Sache, die Sie tun können, ist tatsächlich haben Chopstick erweitern Semaphore (oder Lock). :) Obwohl das dir nichts über die Verwendung direkt kaufen wird. –

0

muss Philospher Sperre erhalten auf beiden chosticks vor dem Start Essen und Pickup leftone wird zunächst dann rechts warten so starten, so starten Methode essen sollten synchronisiert werden. Folgende Methoden werden es funktioniert:

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

public void finishEating(int id) { 
    leftChopstick.release(); 
    rightChopstick.release(); 
} 
1

Stellen Sie sicher, es gibt keine jede Rast- oder synchronisiert Schlüsselwort verwendet. Der Code unten für den Chopstick funktioniert gut für mich ..Kein Profi, aber muss dir eine Idee geben;

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

}