www.wikidata.de-de.nina.az
Das Erzeuger Verbraucher Problem englisch producer consumer problem PCP ist eine klassische abstrakt formulierte Problemstellung der Prozesssynchronisation Auch in der Warenproduktion Logistik und im Supply Chain Management ist das Problem bekannt Zwischenlager konnen im Produktionsprozess positioniert werden Bei der kurzfristigen Warenannahme dienen sie als Puffer zwischen zwei Produktionsstationen Ein Zwischenspeicher kann eine unbegrenzte Kapazitat haben das heisst unbounded buffer oder eine begrenzte Kapazitat haben das heisst bounded buffer Ist das Zwischenlager voll muss die vorgelagerte Produktionsstation die Produktion stoppen Ist das Zwischenlager leer hat die nachgelagerte Produktionsstation nichts zu tun Das Erzeuger Verbraucher Problem beschreibt eine Regelung der Zugriffsreihenfolge auf eine Datenstruktur durch elementerzeugende schreibende und elementverbrauchende lesende Prozesse bzw Threads Die Zugriffsregelung soll verhindern dass ein verbrauchender Prozess auf die Datenstruktur zugreift wenn die Datenstruktur keine Elemente enthalt und eine Entnahme eines Elements aus der Datenstruktur somit nicht moglich ist Wenn die Aufnahmekapazitat der Datenstruktur beschrankt ist soll die Zugriffsregelung ferner verhindern dass ein erzeugender Prozess auf die Datenstruktur zugreift wenn die Aufnahmekapazitat der Datenstruktur bereits ausgeschopft ist Inhaltsverzeichnis 1 Problemformulierung 2 Problemlosung 2 1 Abstrakt 2 2 C 2 3 Java 3 Siehe auch 4 EinzelnachweiseProblemformulierung BearbeitenBetrachtet wird ein System mit Prozessen die sich entweder als Erzeuger oder als Verbraucher verhalten und einer Datenstruktur die von den Prozessen fur die Kommunikation untereinander gemeinsam genutzt wird Es gibt mindestens einen Erzeugerprozess und mindestens einen Verbraucherprozess im System Erzeugerprozesse erzeugen irgendwelche Elemente und legen sie in der gemeinsamen Datenstruktur ab Verbraucherprozesse entnehmen der Datenstruktur Elemente und verarbeiten sie Die Datenstruktur kann unbeschrankt oder beschrankt viele Elemente aufnehmen Sie kann bei nahezu unbeschrankter Kapazitat als Liste oder Stapelspeicher und bei beschrankter Kapazitat z B als Ringpuffer organisiert sein Eine Reihenfolgeregelung Synchronisation ist dann erforderlich wenn Zugriffe auf die Datenstruktur kritische Abschnitte sind Legt ein Erzeugerprozess gerade ein Element in die Datenstruktur oder entfernt ein Verbraucherprozess gerade ein Element so muss verhindert werden dass ein anderer Erzeuger oder Verbraucherprozess diesen Vorgang unterbricht um auch auf die Datenstruktur verandernd zuzugreifen Andernfalls kann es zu einem inkonsistenten Zustand der Datenstruktur kommen ein Verbraucherprozess der Datenstruktur ein Element entnehmen will obwohl die Datenstruktur keine Elemente enthalt die Datenstruktur eine beschrankte Aufnahmekapazitat besitzt und ein Erzeugerprozess bei voll belegter Datenstruktur ein Element ablegen will Greift ein Verbraucherprozess auf eine leere Datenstruktur zu bzw ein Erzeugerprozess auf eine voll belegte Datenstruktur so sollen die Prozesse blockiert und wieder aufgeweckt werden wenn sich der Zustand der Datenstruktur verandert hat Prozesskooperation Eine Losung unter Verwendung des Erzeuger Verbraucher Musters engl producer consumer pattern ist nur dann sinnvoll wenn entweder eine solche Abstraktions Schicht systemisch bedingt notwendig ist Beispielsweise als Sicherheits Abstraktionsschicht oder weil ein System Wechsel Hardware zu Software vorliegt die Anzahl von Verbrauchern und Erzeugern unterschiedlich bzw unbekannt ist Der zweite Punkt lasst sich leicht erklaren wenn man beachtet dass die Zeit Z n displaystyle Z n nbsp die ein Verbraucher fur einen Vorgang N displaystyle N nbsp braucht sich offensichtlich aus der Zeit des Verbrauchers V n displaystyle V n nbsp und des Erzeugers E n displaystyle E n nbsp auf den der Verbraucher zwingend warten muss fur diesen Vorgang so wie der Zeit K displaystyle K nbsp fur die Kommunikation uber das Muster zusammensetzt als Z n V n E n K displaystyle Z n V n E n K nbsp Existiert nun aber fur jeden Verbraucher stets immer genau ein Produzent so konnte der Verbraucher diesen beinhalten also die Produktion selbst vornehmen ohne dabei das Muster anzuwenden da er ansonsten sowieso nur auf den Produzent warten musste Die Zeit fur diese triviale Losung betragt aber nur Z n V n E n displaystyle Z n V n E n nbsp Sie ware also um K displaystyle K nbsp geringer eine Anwendung des Musters in diesem Fall also eine Verlangsamung Problemlosung BearbeitenAbstrakt Bearbeiten Das Erzeuger Verbraucher Problem wird mit Mechanismen der Prozesssynchronisation gelost In den meisten Losungsbeschreibungen werden Semaphore verwendet da diese ausser dem wechselseitigen Ausschluss bei der Ausfuhrung kritischer Abschnitte auch die zuvor verlangte Kooperation zwischen Prozessen unterstutzen Es werden folgende von allen Prozessen gemeinsam genutzte Semaphore benotigt aus Grunden der Allgemeingultigkeit werden fur die Semaphoroperationen die Originalbezeichner P und V verwendet ein binarer Semaphor mutex zum Schutz modifizierender Zugriffe auf die Datenstruktur Will ein Erzeuger oder Verbraucherprozess P2 die Datenstruktur modifizieren so zeigt er dies durch eine P Operation des Semaphors an Sollte gerade ein anderer Prozess P1 die Datenstruktur modifizieren so wird der Prozess P2 blockiert bis der Prozess P1 die V Operation des Semaphors aufruft ein zahlender Semaphor sem read mit dem fur einen Lesezugriff die Verfugbarkeit von Elementen in der Datenstruktur erfasst wird Sollte sich kein Element in der Datenstruktur befinden so bewirkt ein Aufruf der P Operation des Semaphors die Blockade des aufrufenden Verbraucherprozesses Ein Deblockieren des Prozesses erfolgt durch einen Erzeugerprozess der die V Operation des Semaphors aufruft Enthalt die Datenstruktur Elemente so darf ein die P Operation des Semaphors aufrufender Verbraucherprozess mit seinen Aktionen d h mit der Entnahme eines Elements fortfahren ein zahlender Semaphor sem write mit dem fur einen Schreibzugriff die verfugbare Aufnahmekapazitat erfasst wird Sollte sich kein Ablageplatz in der Datenstruktur finden so bewirkt ein Aufruf der P Operation des Semaphors die Blockade des aufrufenden Erzeugerprozesses Ein Deblockieren des Prozesses erfolgt durch einen Verbraucherprozess der die V Operation des Semaphors aufruft Enthalt die Datenstruktur Ablageplatze so darf ein die P Operation des Semaphors aufrufender Erzeugerprozess mit seinen Aktionen d h mit der Ablage eines Elements fortfahren Aufnahmekapazitat der Datenstruktur const N 4 Deklaration der Semaphore semaphor mutex semaphor sem read semaphor sem write Initialisierung der Semaphore init mutex 1 genau einem Prozess wird die Modifikation der Datenstruktur ermoglicht init sem read 0 kein Element befindet sich in der Datenstruktur init sem write N es sind N freie Ablageplatze fur Elemente vorhanden Erzeugerprozess while 1 P sem write Zeige Ablageaktion an P mutex Schutze die Datenstruktur vor Zugriffen anderer Prozesse write element Schreibzugriff auf die Datenstruktur V mutex Hebe den Datenstrukturschutz auf V sem read Informiere einen evtl blockierten Verbraucherprozess uber die Ablage eines Elements Verbraucherprozess while 1 P sem read Zeige Entnahmeaktion an P mutex Schutze die Datenstruktur vor Zugriffen anderer Prozesse read element Lesezugriff auf die Datenstruktur V mutex Hebe den Datenstrukturschutz auf V sem write Informiere einen evtl blockierten Erzeugerprozess uber die Entnahme eines Elements Wenn die Modifikation der Datenstruktur keine kritische Aktion ist dann kann auf den Semaphor mutex verzichtet werden Wenn die Datenstruktur von unbeschrankter Kapazitat ist so wird der Semaphor sem write nicht benotigt C Bearbeiten Ab C 20 sind Semaphore Teil der Sprache Mit C lasst sich die Losung von Dijkstra sehr direkt wiedergeben Der Puffer kann N Teile oder Elemente speichern Das Semaphor number of queuing portions zahlt die gefullten Platze im Puffer das Semaphor number of empty positions zahlt die leeren Platze im Puffer und buffer manipulation dient als Mutex fur die Put und Get Operationen des Puffers Wenn der Puffer voll ist d h number of empty positions ist null wartet der Producer Thread in der number of empty positions acquire Operation Wenn der Puffer leer ist d h number of queuing portions ist null wartet der Verbraucher Thread in der number of queuing portions acquire Operation Die release Operationen geben die Semaphore frei Als Nebeneffekt kann sich ein Thread von der wait Queue in die ready Queue bewegen Die Operation acquire verringert den Semaphorwert bis auf Null Die Operation release erhoht den Semaphorwert Die Variable buffer manipulation ist ein Mutex Die Semaphore Fahigkeit des acquire in einem Thread und des release in einem anderen Thread wird hier nicht benotigt Die Anweisung lock guard anstelle eines Paares von lock und unlock ist C RAII Der lock guard Destruktor sorgt fur die Freigabe der Sperre bei exception Diese Losung kann mehrere Consumer Threads und oder mehrere Producer Threads verarbeiten 1 include lt thread gt include lt mutex gt include lt semaphore gt std counting semaphore lt N gt number of queuing portions 0 std counting semaphore lt N gt number of empty positions N std mutex buffer manipulation void producer for Portion portion produce next portion number of empty positions acquire std lock guard lt std mutex gt g buffer manipulation add portion to buffer portion number of queuing portions release void consumer for number of queuing portions acquire Portion portion std lock guard lt std mutex gt g buffer manipulation portion take portion from buffer number of empty positions release process portion taken portion int main std thread t1 producer std thread t2 consumer t1 join t2 join Java Bearbeiten Die Programmiersprache Java stellt bereits vorgefertigte Klassen bereit um dieses Problem Thread sicher zu losen Eine simple Implementation unter Verwendung einer LinkedBlockingQueue 2 3 ware zum Beispiel in dieser Form moglich import java util concurrent BlockingQueue import java util concurrent LinkedBlockingQueue import java util concurrent ThreadLocalRandom public class ProducerConsumerWithBlockingQueue public static void main String args throws InterruptedException BlockingQueue lt Integer gt blockingQueue new LinkedBlockingQueue lt gt 3 Thread producerThread new Thread gt try for int value 1 value Thread sleep 400 System out println Erzeugt value blockingQueue put value catch InterruptedException e e printStackTrace Thread consumerThread new Thread gt try for int value blockingQueue take System out println t tVerbraucht value Thread sleep ThreadLocalRandom current nextInt 200 800 catch InterruptedException e e printStackTrace producerThread start consumerThread start producerThread join consumerThread join Die verwendete Queue sorgt hierbei automatisch fur die Synchronisation zwischen Verbraucher und Erzeuger Es gibt viele Beispiele einer eigenen Implementierung des Verbraucher Erzeuger Musters in Java Dieses threadsicher zu implementieren ist allerdings nicht trivial da folgende Probleme behandelt werden mussen Eine Losung unter Verwendung der Sprachelemente synchronized sowie wait bzw notify fuhrt genau dann zu einem moglichen Deadlock wenn ein Produzent mittels notify einen Verbraucher aufwecken will dieser allerdings noch nicht wartet wait noch nicht aufgerufen wurde 4 Zur Losung dieses Problems konnen weitere Klassen wie Locks 5 verwendet werden Die LinkedBlockingQueue skaliert als Klasse des Concurrent Packages deutlich besser mit steigender Anzahl Threads als dies mit einer simplen synchronized Losung moglich ware da beim Zugriff auf vorhandene Produkte in der Liste eine Nicht blockierende Synchronisation verwendet wird 6 Siehe auch BearbeitenPhilosophenproblem Raucherproblem Mutex VerklemmungEinzelnachweise Bearbeiten Dijkstra 1965 EWD123 Cooperating sequential processes Kapitel 4 3 The Bounded Buffer https docs oracle com javase 7 docs api java util concurrent LinkedBlockingQueue html Ioan Tinca 2018 The Evolution of the Producer Consumer Problem in Java https www mudraservices com waitnotify html Wait Notify Pitfalls https docs oracle com javase 7 docs api java util concurrent locks Lock html https docs oracle com javase 7 docs api java util concurrent package summary html package description Java Concurrent Package Abgerufen von https de wikipedia org w index php title Erzeuger Verbraucher Problem amp oldid 239025460