2012-04-04 20 views
0

Nach http://en.wikipedia.org/wiki/Producer-consumer_problem Ich möchte P/C-Problem mit Semaphor simulieren. Ich bekomme einen Stillstand und ich weiß nicht, was das Problem ist.Hersteller/Verbraucher mit Semaphore; Deadlock

public static void main(String[] args) { 
     CustomBlockingQueue blockingQueue = new CustomBlockingQueue(); 
     new Thread(new Producer(blockingQueue)).start(); 
     new Thread(new Consumer(blockingQueue)).start(); 
    } 
} 

@SuppressWarnings("serial") 
class CustomBlockingQueue extends LinkedList<Object> { 
    private static final int MAX_SIZE = 10; 

    private Semaphore mutex = new Semaphore(1); 
    private Semaphore fillCount = new Semaphore(0); 
    private Semaphore emptyCount = new Semaphore(MAX_SIZE); 

    @Override 
    public boolean offer(Object e) { 
     try { 
      mutex.acquire(); 
     } catch (InterruptedException e2) { 
      e2.printStackTrace(); 
     } 
     boolean result = super.offer(e); 
     System.out.println("offer " + size()); 
     try { 
      fillCount.release(); 
      emptyCount.acquire(); 
      mutex.release(); 
     } catch (InterruptedException e1) { 
      e1.printStackTrace(); 
     } 
     return result; 
    } 

    @Override 
    public Object poll() { 
     try { 
      mutex.acquire(); 
     } catch (InterruptedException e2) { 
      e2.printStackTrace(); 
     } 
     Object result = super.poll(); 
     System.out.println("poll " + size()); 
     try { 
      emptyCount.release(); 
      fillCount.acquire(); 
      mutex.release(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     return result; 
    } 
} 

class Producer implements Runnable { 
    private CustomBlockingQueue blockingQueue; 
    private Random random = new Random(); 

    public Producer(CustomBlockingQueue blockingQueue) { 
     this.blockingQueue = blockingQueue; 
    } 

    @Override 
    public void run() { 
     while (!Thread.currentThread().isInterrupted()) { 
      try { 
       TimeUnit.SECONDS.sleep(random.nextInt(2)); 
       blockingQueue.offer(new Object()); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

class Consumer implements Runnable { 
    private CustomBlockingQueue blockingQueue; 
    private Random random = new Random(); 

    public Consumer(CustomBlockingQueue blockingQueue) { 
     this.blockingQueue = blockingQueue; 
    } 

    @Override 
    public void run() { 
     while (!Thread.currentThread().isInterrupted()) { 
      try { 
       TimeUnit.SECONDS.sleep(random.nextInt(4)); 
       blockingQueue.poll(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

Mit Semaphore

Semaphore lösen das Problem der verlorenen Weckrufe. In der folgenden Lösung verwenden wir zwei Semaphore, fillCount und emptyCount, um das Problem zu lösen. fillCount ist die Anzahl der Elemente, die im Puffer gelesen werden, und emptyCount ist die Anzahl der verfügbaren Speicherbereiche im Puffer, in die Elemente geschrieben werden können. fillCount wird inkrementiert und emptyCount dekrementiert, wenn ein neues Element in den Puffer gestellt wurde. Wenn der Produzent versucht, leer zu dekrementieren, während sein Wert Null ist, wird der Erzeuger in den Ruhezustand versetzt. Beim nächsten Mal, wenn ein Gegenstand verbraucht wird, wird emptyCount inkrementiert und der Erzeuger wacht auf. Der Verbraucher arbeitet analog.

+1

sparen Sie sich Kopfschmerzen: Verwenden Sie Thread-Safe-Warteschlangen. – jldupont

+0

Einverstanden - dies ist alles für Sie in den Bibliotheken implementiert - keine Notwendigkeit, es auf die harte Tour zu tun! – DNA

+0

Ich möchte für mich dieses Problem mit absichtlich Semaphor – ASD

Antwort

2

Ihre Verriegelung ist in der falschen Reihenfolge:

Bedarf Angebot sein:

 emptyCount.acquire(); 
     mutex.acquire(); 
     doModification(); 
     mutex.release(); 
     fillCount.release(); 

ähnliche Änderung für Umfrage benötigt:

 fillCount.acquire(); 
     mutex.acquire(); 
     doModification(); 
     mutex.release(); 
     emptyCount.release(); 

In Ihrer Implementierung warten Sie auf Semaphore, während Sie den Mutex halten, was Probleme verursacht, weil der andere Thread auf den Mutex warten kann, um einen Semaphor freizugeben.

+0

+1 Sie müssen versuchen, diese Bestellung falsch zu machen - Semaphore P-C Warteschlangen wurden seit den 60er Jahren in Klassenräumen gelehrt und es gibt Dutzende von Beispielen. –

2

Sie könnten stattdessen eine BlockingQueue verwenden, die den Fall des Mutex-Locking übernimmt und auf Sie wartet.

Auf der Seite habe ich eine alte Seite, die die Rassenbedingungen des Produzenten/Verbrauchers demonstriert (im Gegensatz zum falschen Interrupt). Aber meine Umsetzung Semaphore nicht verwenden, so dass ich nicht sicher bin, wird es Ihnen helfen:

http://256stuff.com/gray/docs/misc/producer_consumer_race_conditions/

+0

Ich weiß über BlockingQueue, aber ich möchte für mich dieses Problem mit absichtlich Semaphor lösen. – ASD

+0

Dargestellt @ASD. Ich dachte, ich würde das nur darauf hinweisen. Ich habe auch einen Link zu meiner Produzenten-/Konsumentenseite hinzugefügt. – Gray

+0

Danke für die Antwort, aber ich habe dieses Problem bereits auf diese Weise gelöst (aber ein bisschen anders als du). – ASD