210 likes | 328 Views
Prozeßorientierter Simulator mit Java. Stationen können in Java mit Objekten einer Klasse modelliert werden, ebenso Entitäten. Entitäten sind einfach Datenverbunde mit Attributen und Zustandsvariablen. Die Klassen für Stationen enthalten auch Prozeßroutinen, mit denen ihre Prozesse
E N D
Prozeßorientierter Simulator mit Java Stationen können in Java mit Objekten einer Klasse modelliert werden, ebenso Entitäten. Entitäten sind einfach Datenverbunde mit Attributen und Zustandsvariablen. Die Klassen für Stationen enthalten auch Prozeßroutinen, mit denen ihre Prozesse modelliert werden.
Das natürliche Sprachkonstrukt für Prozeßroutinen wären Koroutinen. Da solche in den meisten Programmiersprachen nicht vorhanden sind, muss man nach einem Ersatz suchen. In Java bieten sich hier Threads an. Damit wird das Simulationsprogramm ein Mehrprozessprogramm, und man muß gegenseitige Störungen verhindern. Das geschieht, indem gefährdete Programmteile wechselseitig ausgeschlossen ausgeführt werden. Der Konstrukt in Java dafür ist synchronized, allgemeiner gesprochen ein Monitor.
Stationsklassen enthalten Konstanten, Variablen und Datenverbunde für Attribute und Zustände, Threads und Prozeduren für Prozeßroutinen und weitere Prozeduren für die Modellbeschreibung, den Bericht, und für Spurtritte. Wenn eine Prozeßroutine das Ende eines Zeitintervalls zu erwarten hat oder auf geplante Ereignisse warten muß, wird sie mit einem Thread modelliert und heißt dann „aktiv“. Prozeßroutinen, die nur auf Entitäten warten, können mit einfachen Prozeduren gebildet werden; wir sprechen dann von passiven Prozeßroutinen.
Muß ein Prozeßthread auf ein Ereignis warten, führt er wait() aus. Ein anderer Prozeß kann ihn mit notify() wieder wecken. Der Simulationsalgorithmus wird von einem eigenen Thread ausgeführt. Er fährt immer dann fort, sobald alle Ereignisaktionen zu einem Zeitpunkt durchgeführt sind, d.h. entweder rechnen die Prozesse der Stationen, oder der Simulationsalgorithmus wird ausgeführt.
Prozeßverzögerung: // Ein Prozess einer Station wartet einen Zeitraum Delta_t // der Simulationszeit ab: public synchronized void warte(double Delta_t){ S.plane_Ereignis(S.Uhr+Delta_t, (Ereignis)this, null); S.PSS_wird_inaktiv(); try{ wait(); // der Prozess schlaeft, bis der Simulator // in der Ereignisroutine notify() ausfuehrt } catch(InterruptedException ign){} } // Prozeß wird geweckt: public synchronized void Ereignisroutine(){ S.PSS_wird_aktiv(); notify(); }
// Prozeß wird geweckt: public synchronized void Ereignisroutine(){ S.PSS_wird_aktiv(); notify(); } Der Simulationsalgorithmus fährt immer dann fort, sobald alle Ereignisaktionen zu einem Zeitpunkt durchgeführt sind, d.h. entweder rechnen die Prozesse der Stationen, oder der Simulationsalgorithmus wird ausgeführt. if (Anz_aktiver_PSSe > 0) { try{ wait(); // der Simulator schlaeft, bis der letzte // aktive Prozess notify() ausfuehrt } catch(InterruptedException ign){}; // aktiv bedeutet hier: PSS bearbeitet gerade ein Ereignis
public synchronized void PSS_wird_aktiv() { // aktiv bedeutet hier: PSS bearbeitet gerade ein Ereignis Anz_aktiver_PSSe ++; } public synchronized void PSS_wird_inaktiv() { Anz_aktiver_PSSe --; if (Anz_aktiver_PSSe == 0) notify(); // kein Stations-PSS mehr aktiv, // d.h. alle Vorgaenge zu diesem Zeitpunkt sind abgelaufen, // der Simulator kann weitermachen }
public class Station { // zum Erweitern public String Stationsname; // Umgebung public Simulation S; public Modell M; public String Name(){return Stationsname;} public void Eingang(Entitaet Kunde) {} }
public class Modell { // zum Erweitern public String Modellbeschreibung, Bericht; public int Spur; public void beginne_Simulation(double t){} // Starte Stationen // Plane Simulationshaltereignis // Lege Simulationshaltezeitpunkt fest // Statistische Zähler auf 0 gesetzt public void Spurdaten(Ereignis E){} // fuer explizit modellierte Ereignisse public void setze_Simulation_fort(double t){} // Lege neuen Simulationshalt fest public void beende_Simulation() {} // Halte Station-Threads an public int Zaehlerstaende(statistischer_Zaehler[] z) {return 0;} // Verweis auf alle statistischen Zaehler public void setze_Zaehler_zurueck() {} }
public class poWSS_Modell extends Modell { // Konstanten: // Zustaende des Bedieners: public final static int frei = 0, belegt = 1; // Arten des Bedienungsbeginns: public final static int sofort = 1, spaeter = 0; // Zustand: public int N; // Anzahl der Kunden im Warteschlangensystem (WSS) public int B; // Bediener frei oder belegt // Attribute des Modells // Statistische Zaehler: public statistischer_Zaehler // integrierend: Kundenzahl, Wartende, Bedienerbelegung, // summierend: Wartezeiten, Sofortbedienungen;
// Experimentplanung: public double Endzeitpunkt; public int Zufallszahlen_Strom; public Zufalls_Zahlen ZZahl; public Simulation S; // Stationsklassen: class Quelle extends Station implements Runnable {} // Modellaspekt: Poisson-Quelle // Simulationsaspekt: Station mit Bedienprozess als Thread, // Verzoegerer fuer Zwischenankuntszeiten
class WSS extends Station implements Runnable { // Modellaspekt: Warteschlangensystem // mit einem Bediener mit zwischen a und b gleichverteilter // Bediendauer und FIFO-Strategie // Simulationsaspekt: Station mit Bedienprozess als Thread, // Warteraum-Klasse, spontane Prozessroutine, // einem Eingang fuer Kunden, // Verzoegerer fuer Bedienzeiten //-------------------------------------------------------------------- class FIFO_Warteraum { // Hilfsvariable Entitaet K; //Zustand int Q; // Anzahl in der Warteschlange Liste Warteschlange = new Liste(); boolean Bediener_wartet_auf_Kunden = false;
public synchronized void Eingang(Entitaet Kunde) { // Passive PSS-Routine, // wechselseitig ausgeschlossen, von mehreren anderen PSSen benutzt // warten auf Kunden K = Kunde; K.Zwischenzeit = S.Uhr; // neuer Zustand Q++; Warteschlange.verlaengere(S.Uhr,null,K); // Statistik: Wartende.akkumuliere(+1); if (Bediener_wartet_auf_Kunden) { Sofortbedienungen.addiere(sofort); } else { Sofortbedienungen.addiere(spaeter); } // Spuraufzeichnung: if (Spur>0) Spurdaten1(); if (Bediener_wartet_auf_Kunden) { S.PSS_wird_aktiv(); notify(); // wecke Bediener } }
public synchronized Entitaet hole_Kunden() { // holt Kunden aus der WS, Teil der aktiven PSS-Routine if (Q == 0) { Bediener_wartet_auf_Kunden = true; S.PSS_wird_inaktiv(); try{ wait(); // dieser Prozess schlaeft, bis ein anderer PSS notify() // ausfuehrt, nachdem er einen Kunden geschickt hat } catch(InterruptedException ign){} } K = Warteschlange.Entitaet_am_Kopf() // Neuer Zustand Q--; Bediener_wartet_auf_Kunden = false; Warteschlange.entferne_Kopf(); // Statistik Wartende.akkumuliere(-1); Wartezeiten.addiere(S.Uhr - K.Zwischenzeit); // Spuraufzeichnung: if (Spur>0) Spurdaten2(); return K; }
// Fuer die Modellbeschreibung: public String beschreibe_Station() {...} // // Spurdatenerzeuger: void Spurdaten1(){...} void Spurdaten2(){...} } // Ende Klasse FIFO_Warteraum
Weiter mit Klasse WSS: public void Eingang(Entitaet Kunde) { WR.Eingang(Kunde); } // Hilfsvariablen double Bediendauer; // Warteraum FIFO_Warteraum WR = new FIFO_Warteraum(); // Attribute double a,b; public Station Ziel; // Initialisierungen: WSS(String Name, double a, double b, Station Ziel, Simulation S, Modell M){...} // Verzoegerer fue die Bedeindauern Verzoegerung Bedienung;
public void run() {// Bedienprozess, Thread: // Hilfsvariable Kunde Entitaet K; do { K = WR.hole_Kunden(); // aus der Warteschlange; warten, wenn diese leer ist Bediendauer = ZZahl.gleichverteilt(a,b); // Zustand B = belegt; //Statistik Bedienerbelegung.akkumuliere(+1); // Spur: if (Spur>0) Spurdaten(); // warten auf Bedienungsende: Bedienung.warte(Bediendauer); // Zustand B = frei; //Statistik Bedienerbelegung.akkumuliere(-1); // Kunde zur naechsten Sation: Ziel.Eingang(K); } while (true); }
// Spurdatenerzeuger: void Spurdaten(){...} // Fuer die Modellbeschreibung: public String beschreibe_Station() {...} // Fuer den Ergebnisbericht: public String berichte() {...} } // Ende der Klasse WSS class Senke extends Station { ...} // Modellaspekt: Senke // Simulationsaspekt: Station, ein Prozess mit einer passiven // Prozessroutine (Eingang), kein Thread
// Ereignisroutine, gibt es auch bei prozessorientierter Simulation: class Simulationshaltereignis extends Ereignis { public void Ereignisroutine(){ // Simulationshalt, aber die Simulation kann danach // fortgesetzt werden, mit setze_fort(neue Endzeit); // Bis zur aktuellen Uhrzeit akkumulieren: Kundenzahl.akkumuliere(0); Wartende.akkumuliere(0); Bedienerbelegung.akkumuliere(0); Bericht = ... } }
Weiter mit Klasse poWSS_Modell: //Stationen mit ihren Prozessen: Senke Loch; // Variable Typ Senke; WSS MG1; // Variable Typ WSS Thread Bedienprozess; // Variable fuer den Prozess des Bedieners Quelle Ankuenfte; // Variable Typ Quelle Thread Ankunftsprozess; // Variable fuer den Prozess der Quelle // Simulationshaltereignis: Simulationshaltereignis SimHalt;
// Konstruktor, initialisiert ein Modell: public poWSS_Modell(double lambda, double a, double b, int Stromnummer, int Spur0) { ZZahl = new Zufalls_Zahlen(Stromnummer); Zufallszahlen_Strom = Stromnummer; S = new Simulation(this,2); // muss vor den Stationen mit ihren Prozessen instantiert werden // 2 ist die Anzahl der Stationsprozesse // Einrichten der Stationen und ihrer Prozesse: Loch = new Senke("Loch", S, this); MG1 = new WSS("MG1", a, b, Loch, S, this); Bedienprozess = new Thread( (Runnable)MG1); Ankuenfte = new Quelle("Ankuenfte", lambda, MG1, S, this); Ankunftsprozess = new Thread( (Runnable)Ankuenfte); Kundenzahl = new integrierender_Zaehler("Kundenzahl",S); Wartende = new integrierender_Zaehler("Wartende",S); Bedienerbelegung = new integrierender_Zaehler("Bedienerbelegung",S); Wartezeiten = new summierender_Zaehler("Wartezeiten"); Sofortbedienungen= new summierender_Zaehler("Sofortbedienungen"); Modellbeschreibung = ... }