/*************************************************************/ /* Prof. Dr. Carsten Vogt */ /* FH Koeln, Fak. 07 / Nachrichtentechnik */ /* http://www.nt.fh-koeln.de/vogt */ /* */ /* Lösung des Erzeuger-Verbraucher-Problems mit Semaphoren */ /*************************************************************/ import java.util.concurrent.*; // grundlegende Werte für die Simulation class Basiswerte { static int gesamtdauer = 20000; // Gesamtlaufzeit des Programms (in ms) static int erzeugungsdauer = 1000; // Zeitdauer zum Erzeugen eines Werts (außerhalb des kritischen Abschnitts) static int verbrauchsdauer = 5000; // Zeitdauer zum Verbrauchen eines Werts (außerhalb des kritischen Abschnitts) static int schreibdauer = 1000; // Zeitdauer zum Schreiben eines Werts in den Puffer (im kritischen Abschnitt) static int lesedauer = 1000; // Zeitdauer zum Lesen eines Werts aus dem Puffer (im kritischen Abschnitt) static int pufferkapazitaet = 3; // Kapazität des Puffers } // Pufferspeicher class Puffer { // Attribute private int inhalt[]; // Werte, die im Puffer gespeichert sind (Array wird als Ringpuffer benutzt) private int kap; // Kapazität = Anzahl der Werte, die der Puffer maximal aufnehmen kann private int leseindex, schreibindex; // Index bzgl. 'inhalt[]', mit dem die nächste Lese- bzw. Schreiboperation stattfindet Semaphore voll, leer; // Semaphoren, die blockieren, wenn der Puffer voll bzw. leer ist. Semaphore wA; // Semaphor, der den wechselseitigen Ausschluss bei Pufferzugriffen sicherstellt. // Konstruktor Puffer() { kap = Basiswerte.pufferkapazitaet; inhalt = new int[kap+1]; // Array hat einen Platz mehr als die Kapazität, um die Fälle "Puffer ist leer" ('leseindex'=='schreibindex') // und "Puffer ist voll" ('schreibindex' steht eine Position hinter 'leseindex') unterscheiden zu können leseindex = schreibindex = 0; voll = new Semaphore(kap); // Der Puffer ist zu Beginn leer => Der 'voll'-Semaphor kann 'kap'-mal heruntergezählt werden, bevor er blockiert leer = new Semaphore(0); // Der Puffer ist zu Beginn leer => Der 'leer'-Semaphor kann 0-mal heruntergezählt werden, bevor er blockiert wA = new Semaphore(1); // wechselseitiger Ausschluss } // 'schreibe()' schreibt den Wert 'wert' in den Puffer (wechselseitig ausgeschlossen zu 'lies()') void schreibe(int wert) { // blockiere, wenn der Puffer voll ist try { voll.acquire(); } catch (Exception e) { }; // belege den Puffer (wechselseitiger Ausschluss) try { wA.acquire(); } catch (Exception e) { }; System.out.println("Schreiben beginnt"); // schreibe Wert in den Puffer und setze 'schreibindex' zyklisch um 1 weiter try { Thread.sleep(Basiswerte.schreibdauer); } catch (Exception e) { } inhalt[schreibindex] = wert; schreibindex = (schreibindex+1)%(kap+1); System.out.println(" "+wert+" geschrieben"); ausgabe(); System.out.println("Schreiben endet"); // entblockiere Thread (konkret: Verbraucher-Thread, der möglicherweise in 'lies()' wartet) leer.release(); // gib Puffer frei (wechselseitiger Ausschluss) wA.release(); } // Ende 'schreibe()' // 'lies()' liest einen Wert aus dem Puffer und liefert ihn zurück (wechselseitig ausgeschlossen zu 'schreibe()') synchronized int lies() { // blockiere, wenn der Puffer leer ist try { leer.acquire(); } catch (Exception e) { }; // belege den Puffer (wechselseitiger Ausschluss) try { wA.acquire(); } catch (Exception e) { }; System.out.println("Lesen beginnt"); // schreibe Wert in den Puffer und setze 'leseindex' zyklisch um 1 weiter try { Thread.sleep(Basiswerte.lesedauer); } catch (Exception e) { } int gelesen = inhalt[leseindex]; leseindex = (leseindex+1)%(kap+1); System.out.println(" "+gelesen+" gelesen"); ausgabe(); System.out.println("Lesen endet"); // entblockiere wartenden Thread (konkret: Erzeuger-Thread, der möglicherweise in 'schreibe()' wartet) voll.release(); // gib Puffer frei (wechselseitiger Ausschluss) wA.release(); return gelesen; } // Ende 'lies()' // 'ausgabe()' gibt den Pufferinhalt auf den Bildschirm aus void ausgabe() { if (leseindex==schreibindex) { System.out.println(" Puffer leer"); return; } System.out.print(" Pufferinhalt:"); if (leseindex