6.3 Ereignisbasierte Systeme Ereignis (event) : eine Ereignis-Quelle (event source, publisher) generiert Benachrichtigung (event notification), an der i.a. mehrere Ereignis-Senken (event sinks, subscribers) interessiert sind. Z.B. Pixelpark-Aktie fällt unter 1,2! Druck steigt über 4,5! Für die Quelle ist es irrelevant, wer auf ein Ereignis wie reagiert. Die Senken sind an ganz bestimmten Ereignissen interessiert.
Verschiedenartige Ereignisse werden durch verschiedene Ereigniskanäle (event channels) repräsentiert, die auch gemäß den Ereignisnachrichten getypt sein können
Verschiedenartige Ereignisse werden durch verschiedene Ereigniskanäle (event channels) repräsentiert, die auch gemäß den Ereignisnachrichten getypt sein können QuelleSenken nachrichtenbasierter Ereigniskanal (hier im Beispiel mit 3 Senken) Aufrufbasierte Variante: asynchroner Prozeduraufruf!
Senke für Ereignis(se) kann gleichzeitig Quelle anderer Ereignis(se) sein. Ereignisbasiertes System (event-based system) = Prozeßnetz aus Ereignisquellen und -senken Prozeß erklärt sich dynamisch zur Senke für einen Ereigniskanal – abonniert das Ereignis (subscription) und kann das Abonnement später wieder kündigen (cancellation).
6.3.1 Ereignisorientierte Programmierung Typischer aufrufbasierter Ereigniskanal: interface Event { void signal(Notification n); // forks all subscribers, passing n void subscribe(Handler h); // subscribes event handler h void cancel(Handler h); // cancels subscription } interface Handler { void handle(Notification n); // handles n }
Ereignisquelle für ein Ereignis lowPressure :... lowPressure.signal(pressure);... Behandlung des Ereignisses:... Handler h = new Handler (){ void handle(Float press){..hier.. }};... lowPressure.subscribe(h);... lowPressure.cancel(h);...
6.3.2 Das Beobachter-Muster (observer pattern) ist ein objektorientiertes Entwurfsmuster (design pattern), das als sequentielle Variante der ereignisbasierten Interaktion betrachtet werden kann: Subject attach(Observer) detach(Observer) notify() Observer update() ConcreteSubject ConcreteObserver update() *
s:ConcreteSubject x:ConcreteObserver y:ConcreteObserver s.attach(this);
s:ConcreteSubject x:ConcreteObserver y:ConcreteObserver s.attach(this);
s:ConcreteSubject x:ConcreteObserver y:ConcreteObserver s.attach(this); notify(); o[1].update(); o[2].update();
s:ConcreteSubject x:ConcreteObserver y:ConcreteObserver s.attach(this); notify(); o[1].update(); o[2].update(); notify(); o[1].update(); o[2].update(); Analogie:Ereigniskanal: event.subscribe(handler) Beobachter-Muster: subject.attach(observer)
Unterstützung durch java.util : interface Observer { void update(Observable o, Object notification); } class Observable { public synchronized void addObserver(Observer o); public synchronized void delObserver(Observer o); public void notifyObservers(Object notification);..... }
6.3.3 Das Ereignis-Modell von Java orientiert sich am Beobachter-Muster: event listener = Beobachter (= Ereignissenke) event source = Beobachteter (= Ereignisquelle) event type + event source (= Ereigniskanal/typ) (event type in AWT per Namenskonvention) event object = Benachrichtigung (für GUI-Ereignisse: Paket java.awt.event u.a.)
Abonnieren eines Ereignisses: event type X + event source Ereigniskanal: event.subscribe(handler); Beobachter-Muster: subject.attach(observer); Java AWT: source.addXListener(anXListener); z.B. button.addActionListener( new ActionListener(){ public void actionPerformed (ActionEvent e){ Button b = e.getSource();...} } ); Ereignisquelle ist hier ein Button -Objekt: das Ereignis wird durch Klicken auf die entsprechende Taste der GUI ausgelöst.
6.4 Verteilte Algorithmen bewerkstelligen Problemlösung durch Kooperation kommunizierender Prozesse: alle Beteiligten kennen ihre Partner (peers) und deren Funktionsweise; Partner sind häufig gleichberechtigt, haben auch oft identischen Code, verwenden meist direkte Interprozeßkommunikation (ohne explizite Kanäle).
Problem: Sichere Nachrichtenübertragung von A nach B unter Verwendung zweier unsicherer Kanäle, Sender A Empfänger B auf denen sporadisch Nachrichten verlorengehen Das Alternating-Bit-Protokoll Lösungsidee: Nachrichten quittieren – neue Nachricht erst dann schicken, wenn Quittung eingetroffen; evtl. letzte Nachricht wiederholen.
SenderEmpfänger Nachricht Quittung
SenderEmpfänger Nachricht Quittung Nachricht Quittung (timeout) ? Ist letzte Nachricht angekommen, oder muß sie wiederholt werden ?
Nachrichten und Quittungen durchnumerieren – aber modulo 2 genügt ! Unsichere Kanäle mit folgender Spezifikation: interface Channel { void send(Data d, boolean b); // ersetzt (data,bit) durch (d,b) // - aber manchmal auch nicht Data data; boolean bit; // anfangs false } Kanal für Nachrichten: msg Kanal für Quittungen: ack
SenderEmpfängerboolean bit = false; do{do{ if(ack.bit == bit){ if(msg.bit != bit){ data = produce(); consume(msg.data); bit = !bit;} bit = !bit;} msg.send(data,bit); ack.send(null,bit); }while(true);}while(true);
6.4.2 Verteilter wechselseitiger Ausschluß Zentralisierte Lösungen: Semaphor durch Kanal simulieren (6.1.1)6.1.1 Boolesches Semaphor durch Prozeß simulieren, mit synchroner Kommunikation über 2 Kanäle p,v : while(true){ p.recv(); v.recv(); } Benutzung: p.send();... kritischer Abschnitt v.send();
Verteilte Lösung:unter den beteiligten Prozessen eine Marke kreisen lassen – wer sie besitzt, darf kritischen Abschnitt ausführen = Steuerungs-Prozeß, läßt die Marke kreisen, recv();... peer[i].send(); und interagiert lokal mit seinem Anwendungs- Prozeß (hier 0,1,2)
Jedes System aus Steuerungs- und Anwendungsprozeß hat lokale Sperre mit Operationen lock/unlock Initialisierung bei jedem System: lock(); Nummer eines jeden Systems: me Jeder Steuerungs-Prozeß verhält sich so: do{recv(); unlock(); lock(); peer[me 1].send(); }while(true);
6.4.3 Replizierte Datenhaltung = Datenobjekt wird in mehreren Kopien bei mehreren Prozessen geführt Motivation: schnelle und sichere Verfügbarkeit im Netz Problem:Konsistenzerhaltung bei Datenänderung Problemlösung: mit Rundsendung (broadcast) an alle Beteiligten (replicated data)
Postulierte Operationen: interface Broadcasting { void bsend(Msg msg); // sende msg an alle Beteiligten einschließlich // Absender (jeder erhält Kopie in privatem Puffer) Msg recv(); // entnimm Nachricht aus Puffer } Atomares Senden wird gefordert, d.h. unterschiedliche Empfangsreihenfolgen bei nebenläufigem Senden sind ausgeschlossen! Rechtfertigung:häufig entsprechende Hardware- Unterstützung, z.B. in Lokalnetzen
Voraussetzung: Nur ein Datenobjekt Data mit einer Operation op class Data extends Broadcast { public static void op(Arg arg){ bsend(arg); }... // Daten static void realop(Arg arg) {.....} // Steuerungs-Prozeß:... do{Arg arg = recv(); realop(arg);} while(true);... }