6.3 Ereignisbasierte Systeme Ereignis (event) : eine Ereignis-Quelle (event source, publisher)...

Post on 05-Apr-2015

112 views 6 download

transcript

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

Quelle Senken

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<Notification> {void signal(Notification n);

// forks all subscribers, passing n void subscribe(Handler<Notification> h);

// subscribes event handler hvoid cancel(Handler<Notification> h);

// cancels subscription}

interface Handler<Notification> {void handle(Notification n);

// handles n }

Ereignisquelle für ein Ereignis lowPressure :...lowPressure.signal(pressure);...

Behandlung des Ereignisses:...Handler h = new Handler<Float>(){

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:

Subjectattach(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.attach(this);

s:ConcreteSubject x:ConcreteObserver y:ConcreteObserver

s.attach(this);

s.attach(this);

notify(); o[1].update(); o[2].update();

s:ConcreteSubject x:ConcreteObserver y:ConcreteObserver

s.attach(this);

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 durchKlicken auf die entsprechende Taste der GUI ausgelöst.

6.4 Verteilte Algorithmen

bewerkstelligen Problemlösung durch Kooperationkommunizierender 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 Bunter Verwendung zweier unsicherer Kanäle,

Sender A Empfänger B

auf denen sporadisch Nachrichten verlorengehen.

6.4.1 Das Alternating-Bit-Protokoll

Lösungsidee: Nachrichten quittieren – neue Nachricht erst dann schicken, wenn Quittung eingetroffen; evtl. letzte Nachricht wiederholen.

Sender Empfänger

Nachricht

Quittung

Sender Empfänger

Nachricht

Quittung

Nachricht

Quittung

(timeout)

? Ist letzte Nachrichtangekommen, 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

Sender Empfänger

boolean bit = false; boolean 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)

Boolesches Semaphor durch Prozeß simulieren,

mit synchroner Kommunikation über 2 Kanäle p,v:

while(true){ p.recv(); v.recv(); }

Benutzung: p.send();... kritischer Abschnittv.send();

Verteilte Lösung: unter den beteiligten Prozessen

eine Marke kreisen lassen – wer

sie besitzt, darf kritischen Abschnitt

ausführen.

0

2

1

= 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[me1].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<Msg> { 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<Arg> {public static void op(Arg arg){ bsend(arg); }

... // Daten static void realop(Arg arg) {.....}

// Steuerungs-Prozeß: ... do{Arg arg = recv();

realop(arg);}while(true);

...}