Inhalt ! Was ist neu? | Gästebuch
Sie sind hier: www.netz-meister.de > Marko Meister > more than you get wi ... > Papers > Ein Kommunikationsme ... > 4 Implementierung










... aber ich werde alles geben,
daß er Wirklichkeit wird!

Der Traum ist aus
aus: "Keine Macht für Niemand"
Ton Steine Scherben (1972)

4

Implementierung

 

Aufgrund der Systematisierung und der Bestandsanalyse wurden im vorangegangenen Abschnitt Überlegungen angestellt, wie das Kommunikationsproblem in verteilten virtuellen Umgebungen gelöst werden kann. Einige der Überlegungen führten zur Entwicklung von Mechanismen. Diese Mechanismen wurden in einer Prototyplösung implementiert, um ihre Funktionsfähigkeit praktisch zu prüfen.

Wesentliche Ziele bei der Entwicklung des Systems waren Skalierbarkeit und eine flexible, erweiterbare Struktur.

Im Einzelnen realisiert der Prototyp den Eventtransport über das Netzwerk, die Verwaltung der OI, den Abonnementmechanismus, den Übergang der Objektkontrolle, Objektverhalten sowie minimale Visualisierung. Mechanismen wie automatische (positionsabhängige) Abonnierung, Interaktionserkennung und Interaktionsauflösung sowie Objektcodetransfer wurden noch nicht implementiert.

Der Prototyp stellt einen ersten Ansatz für eine verteilte virtuelle Umgebung zur Verfügung. In einem solchen System müssen neben der Implementation der vorgestellten kommunikationsrelevanten Mechanismen noch andere Probleme gelöst werden. Diese Probleme wurden im Abschnitt 3 (ab Seite 32) dargestellt.

4.1

Voodie Prototyp

 

Der Voodie Prototyp stellt die Prototypimplementation für die Mechanismen dar. Er besteht aus einer Applikation, die die eigentlichen Mechanismen und die notwendigen Verwaltungsmodule implementiert und einer Visualisierungsanwendung. Die derzeitige Version des Prototypen besteht aus ca. 4500 Zeilen C++ Code und wurde auf einer Indigo2 Maximum Impact Grafikworkstation mit TRAM Option der Firma Silicon Graphics Inc. unter Irix 6.2 entwickelt. Der vollständige Quellcode liegt der Arbeit auf einem digitalen Speichermedium bei.

Die Implementierung der Verwaltungsmodule und der Voodie Objekte ist objektorientiert und greift auf Funktionalitäten der Standard C++ Bibliothek (/JOS96/, /STL96/) zurück.

Die Applikation besteht aus einer Reihe eigenständiger Module, die in separaten Threads ablaufen. Dabei wurde zur Implementation die POSIX 1003.1c Threads API (pthreads, /NIC96/) benutzt. Die einzelnen Module kommunizieren dabei über den Austausch von Ereignissen (Events). Dieser Austausch erfolgt über globale, modulspezifische Eventqueues. Bei der Entscheidung, für die Implementierung der einzelnen Module Threads zu verwenden, stand die mögliche Benutzung von Mehrprozessormaschinen an zweiter Stelle. Hauptgrund für den Einsatz von Threads waren softwaretechnologische Überlegungen. Durch den Einsatz von separaten, getrennt ausgeführten Modulen für die Verwaltung, ist eine sehr gute Trennung der einzelnen Module möglich.

Der Prototyp hat verschiedene Aufgaben zu lösen. Eine Aufgabe ist die Verwaltung der Objekte, eine weitere Aufgabe stellt die Kommunikation der Systeme verschiedener Teilnehmer über das Netzwerk dar. Die Visualisierung und die Verarbeitung von Eingaben sind weitere Aufgaben, die durch den Prototyp gelöst werden müssen. Da die einzelnen Module des Systems miteinander kommunizieren müssen, ist auch das Management dieser Kommunikation eine Aufgabe des Prototypen. Ausgehend von diesen Aufgaben wurde das System in folgende Module unterteilt:

Interaktionsdämon
Der Interaktionsdämon (ID) verwaltet Objekte des Voodie Systems. Über ihn werden Objekte generiert und gelöscht.

Net_listener / Net_sender
Diese Module ermöglichen den Transport von Ereignissen von einer Station zu einer anderen.

Renderer / console_listener
Das Renderer Modul verarbeitet Visualisierungsereignisse, console_listener setzt Eingaben in entsprechende Ereignisse um. Im Prototyp fungieren diese Module als Interface zu einer separaten Visualisierungsanwendung. Diese Anwendung verarbeitet die durch das Renderer Modul ausgegebenen Ereignisse weiter und liefert in Abhängigkeit von den Eingaben des Benutzers Daten an das Console_listener Modul.

Distributor
Ein weiteres Modul, der Distributor, verteilt die Ereignisse an die entsprechenden Module und ermöglicht damit die Kommunikation zwischen den einzelnen Modulen.

Voodie Objekte
Objekte im Voodie System werden wie die Verwaltungsmodule als separate Threads implementiert. Dies ermöglicht zum einen eine flexible und abgeschlossene Implementierung der Objekte und zum anderen auch die Implementation von zusätzlichen Verwaltungsmodulen. Im Prototyp wurde z.B. der OI-Verwalter als spezielles Voodie Objekt implementiert.

Abbildung 9 verdeutlicht den Zusammenhang und die Aufgaben der Module.

Abbildung 9: Interner Aufbau der Voodie Applikation


4.2

Graphische Ausgabe

 

Die Implementierung der Mechanismen beinhaltet keine Funktionalität zur Visualisierung der Voodie Objekte. Durch das Renderer Modul wird lediglich der Inhalt der RENDER Events auf den Standardausgabekanal ausgegeben. Derzeit werden diese Ausgaben von einer eigenständigen Renderapplikation weiterverarbeitet. Für die Implementierung der Renderapplikation wurde das OpenGL API (/NEI93/) und die GLUT Bibliothek (/KIL96/) benutzt. Die Renderapplikation läuft als Koprozeß parallel zur Hauptanwendung (Voodie Applikation).

Die Kommunikation der beiden Prozesse erfolgt über eine Duplex Pipe. Das bedeutet, daß auf den Standardausgabekanal (stdout) der Voodie Applikation von der Renderapplikation aus zugegriffen werden kann. Der Standardeingabekanal (stdin) der Voodie Applikation wird von der Renderapplikation mit Daten versorgt. Abbildung 10 zeigt die Kommunikation der beiden Prozesse.

Abbildung 10: Kommunikation zwischen Render- und Voodie Applikation

4.3

Eventdatenstruktur

 

Die gesamte Kommunikation im Voodie System ist ereignisorientiert. Dabei besitzen die Ereignisse (Events) die Struktur TYPE
FROM_HOST
FROM_MODULE
TO_HOST
TO_MODULE
MESSAGE.

Diese Struktur ist die derzeitig implementierte Struktur für Events. Sie orientiert sich sehr stark an der internen Implementation des Voodie Prototyps.

mögliche Verbesserungen

In der bisherigen Eventdatenstruktur sind keine Objektidentifikatoren enthalten. Sollen Voodie Objekte identifiziert werden, so geschieht dies derzeit über den Messageteil des Events. Diese Identifikatoren können aber fest in die Datenstruktur eingebaut werden, indem die Module auch als Voodie Objekte behandelt werden. Diese Objekte besitzen dann reservierte ObjektIDs und sind nicht abonnierbar. Aufgrund bisheriger Erfahrungen und Tests sollten die Events in der Form:

 

TYPE
SENDER
RECEIVER
MESSAGE

vorliegen.
Dabei sind SENDER und RECEIVER jeweils ObjektIDs.

Dadurch könnten sich z.B.: folgende (vorbelegte und damit reservierte) ObjektIDs ergeben:

		DISTRIBUTOR   ...  Objekt 0
		NET_SENDER    ...  Objekt 1
		NET_LISTENER  ...  Objekt 2
		RENDERER      ...  Objekt 3
		CONSOLE       ...  Objekt 4
		ID            ...  Objekt 5
		OI_OBJECT     ...  Objekt 6
	      

Eine ObjektID kann dann - unter Hinzunahme einer Portnummer - in der Form: HOSTNAME:PORTNUMMER/OBJEKTNUMMER

dargestellt werden. Beispielhaft sähen ObjektIDs folgendermaßen aus: parrot.informatik.hab-weimar.de:3490/2
parrot.informatik.hab-weimar.de:3490/ID
141.54.12.13/7 (default Port)

Wenn diese Darstellung um den Namen des Protokolls erweitert wird, kann eine URL (/LEE94a/, /LEE94b/) konforme Schreibweise für die Identifizierung eines Voodie Objektes benutzt werden: voodie://parrot.informatik.hab-weimar.de:3490/ID

4.4

Netzwerkmodule / Eventtransfer

 

Der Netzwerkverkehr im Voodie System basiert auf UNIX Stream Sockets (/BRO94/, /STE92/, /WRI95/, /RAG93/, /HAL96/).

Stream Sockets stellen ein Interface für die Netzwerkkommunikation zur Verfügung, welches verindungsorientierte Kommunikation ermöglicht. Dadurch können Datenströme beliebiger Länge von einer Station zu einer anderen übertragen werden. Die Verwendung von Stream Sockets bringt aber auch einen nicht unerheblichen Aufwand für das Verbindungsmangement mit sich, da der Datentransport Methoden zur Fehlerkorrektur beinhaltet. Durch die Benutzung von verbindungsloser, paketorientierter Kommunikation (realisierbar z.B. durch den Einsatz von UDP) wäre eine Performancesteigerung beim Datentransport möglich. In diesem Fall müßte aber die Notwendigkeit einer Fehlerkontrolle und Empfangsbestätigung geprüft werden.

Da die Übertragung der Ereignisse noch optimiert werden muß, diese Aufgabe aber für das Funktionieren des Prototypen nicht relevant ist, wurden im Rahmen der Lehrveranstaltung Rechnernetze II des Studienganges Informatik der Bauhaus-Universität Weimar im Sommersemester 1997 Belegaufgaben zur Optimierung der Ereignisübertragung ausgegeben. Die Ergebnisse dieser Arbeiten werden erst nach Abschluß dieser Arbeit vorliegen. Die Ergebnisse sollten auf jeden Fall auf eine Verwendbarkeit in zukünftigen Voodie Implementationen hin untersucht werden.

Die Netzwerkmodule im Voodie System (Net_Listener, Net_Sender), haben die Aufgabe, Events von einer Station zu einer anderen zu übertragen. Das Modul Net_Sender hat die Aufgabe, Events an eine entfernte Station zu schicken. Das Modul Net_Listener empfängt Events, die von anderen Stationen abgeschickt wurden.

Bei der Übertragung der Events wird folgendes "low-level" Eventtransferprotokoll benutzt (Eventlänge unbegrenzt, Streamvariante):

	    LISTENER : erwarte Verbindung
	    SENDER   : stelle Verbindung her
	    LISTENER : sende Begrüßung
	                   This is VOODIE <Version>
	                   accepting Events: 
	                   (TYPE FROM_HOST FROM_MODULE
	                   TO_HOST TO_MODULE MESSAGE end of message)
	    SENDER   : lese Begrüßung
	    wiederhole   
  	         SENDER   : sende ein Paket (einen Teil, einige Byte
	                           der Zeichenkette)
	         LISTENER : lese ein Paket
	         LISTENER : sende Empfangsbestätigung
	                        received <num> Bytes. ok!
                 SENDER   : erwarte und lese Empfangsbestätigung
	         LISTENER : hänge das Paket an die bereits
	                           empfangene Zeichenkette an
	    bis die gesamte Zeichenkette übertragen wurde.   
	    
	    SENDER   : sende
                           end of message
            LISTENER : sende Bestätigung, Verbindung abbrechen
	    
	    SENDER   : lese Bestätigung, Verbindung abbrechen
	    
	    LISTENER : empfangene Zeichenkette ist Rückgabewert
	  

Da die Events uncodiert übertragen werden, ist es möglich, ein Event von Hand über das Netzwerk an eine Voodie Station zu übertragen. Dies könnte mit telnet z.B. so aussehen:

 parrot 102 /usr/people/meister1>telnet 141.54.24.13 3490
 Trying 141.54.24.13...
 Connected to 141.54.24.13.
 Escape character is '^]'.
 This is Voodie v0.002, feb,mar 97,(p) by mm
 accepting Events: (TYPE FROM_HOST FROM_MODULE TO_HOST TO_MODULE
MESSAGE end of message) ...
 DATA LOCAL INPUT 141.54.24.13 ID CREATE_OBJECT CLASS = voodie_first_object_c
end of message
 received 77 Bytes. ok!
 Connection closed by foreign host.
 parrot 103 /usr/people/meister1>

zeitliche Ordnung von Ereignissen

Für die Mechanismen, die auf dem Austausch von Ereignissen basieren, ist es nicht notwendig, die Ereignisse zeitlich zu ordnen. Die derzeitig implementierten Mechanismen benötigen eine solche Ordnung nicht. Für in Zukunft zu entwickelnde Mechanismen ist es aber durchaus denkbar, daß eine zeitliche Ordnung der Ereignisse hergestellt werden muß. Lamport schlägt in /LAM78/ einen verteilten Algorithmus vor, der zu diesem Zweck eingesetzt werden könnte.

4.4

Wichtige Ereignisse (Events) in Voodie

 

Im Voodie System sind sehr viele Events möglich. Einige dieser Events wurden in den vorangegangenen Ausführungen bereits erwähnt. Die meisten dieser Events werden automatisch als Reaktion auf andere Events generiert. Prinzipiell können alle diese Events auch explizit von außen durch einen Operator an das jeweilige Modul bzw. Voodie Objekt geschickt werden. Für die Demonstration der Mechanismen werden aber lediglich die folgenden Events benötigt:

Global Exit
Typ: EXIT Name: GLOBAL_EXIT
From Host LOCAL To Host LOCAL
From Module INPUT To Module DISTRIBUTOR
Message <error_string>
Beschreibung Alle Module beenden, Objekte zerstören, Programm beenden.
Create Object
Typ: DATA Name: CREATE_OBJECT
From Host LOCAL To Host LOCAL
From Module INPUT To Module ID
Message CREATE_OBJECT CLASS = <a_valid_class_name>
Beschreibung Generiere auf der lokalen Station ein Objekt der Klasse <a_valid_class_name> (CREATE_OBJECT Event).
Send All OI
Typ: DATA Name: SEND_ALL_OI
From Host LOCAL To Host <TO HOST>
From Module INPUT To Module ID
Message SEND_ALL_OI
Beschreibung Bitte um Sendung aller OI der Station <to_host> (SEND_ALL_OI Event).
Typ: DATA
From Host LOCAL To Host LOCAL
From Module INPUT To Module OBJECTS
Message id = <num> STATE = EXIT
Beschreibung Weise das Voodie Objekt mit der Identifikation <num> der lokalen Station an, seinen Status auf EXIT zu setzen.
Subscribe OI
Typ: DATA Name: SUBSCRIBE OI
From Host LOCAL To Host LOCAL
From Module INPUT To Module OBJECTS
Message id = 1 SUBSCRIBE OI = <num>
Beschreibung Anweisung an das OI-Objekt, den OI, der sich an der Position <num> der aktuellen OI-Liste befindet, zu abonnieren. (SUBSCRIBE OI Event, nicht zu verwechseln mit SUBSCRIBEEvent).

Die derzeitige Implementation des graphischen Interfaces erlaubt lediglich das Senden dieser Events. Eine Aufstellung aller möglichen Ereignisse findet sich im Anhang B "Mögliche Events in Voodie")

4.5

Objektabonnement

 

Ein Objekt kann nur dann abonniert werden, wenn zumindest sein OI bekannt ist. Im OI sind Informationen zur Klasse des Objektes und die eindeutige Identifizierung (ObjektID) enthalten. Das Abonnement eines Objektes geschieht in drei Phasen. In Abbildung 11 sind die Phasen beim Objektabonnement zum besseren Verständnis graphisch dargestellt.

Abbildung 11: Phasen beim Objektabonnement

Phase 1:
Die OI werden in der ersten Phase des Objektabonnements übertragen.

Station 2 sendet zu einem Zeitpunkt t1 ein SEND_ALL_OI Ereignis an eine andere Station (Station 1). Diese Station reagiert auf dieses Ereignis, indem sie alle Objekte anweist, einen OI an die erste Station zu senden. Diese OI kommen irgendwann zwischen den Zeitpunkten t2 und t3 bei Station 2 an.
Soll ein Objekt (Masterobjekt) der Station 1 von Station 2 abonniert werden, so ergibt sich in einer zweiten Phase folgender Ablauf:

Phase 2:
Auf Station 2 wird ein Slaveobjekt generiert (anhand der Daten im OI).
Das Slaveobjekt sendet dann ein SUBSCRIBE Event an das Masterobjekt auf Station 1 (ObjektID stand im OI) und wird somit zum Abonnent des Masterobjektes.

Phase 3:
Das Masterobjekt (auf Station 1) sendet nun während der dritten Phase UPDATE Events an das neu generierte Objekt Slaveobjekt (auf Station 2), bis es ein UNSUBSCRIBE Event vom Slaveobjekt erhält.

Die OI werden durch das OI-Objekt verwaltet. Das Abonnement eines Objektes einer anderen Station kann von außen durch Senden eines SUBSCRIBE OI = <oi_num> Events an das OI-Objekt eingeleitet werden. Das OI-Objekt veranlaßt dann die Erzeugung des Slaveobjektes

4.7

Übergabe der ObjektkontrolleObjektabonnement

 

Es sind zwei Ausgangssituationen für den Übergang der Objektkontrolle denkbar:

[A1] Ein Slaveobjekt will die Objektkontrolle übernehmen.

Das Slaveobjekt sendet ein REQ_OWNER Event an das Masterobjekt. Das Masterobjekt entscheidet nun, ob es die Kontrolle abgeben will.
Wenn nein, passiert nichts.
Wenn ja, sendet das Masterobjekt ein SET_OWNER Event an das Slaveobjekt und wird selbst zu einem Slaveobjekt indem es seinen Status auf SLAVE setzt. Das Objekt wird dann automatisch Abonnent seines ehemaligen Slaveobjektes.
Wenn das Slaveobjekt das SET_OWNER Event erhält, setzt es seinen Status auf MASTER und nimmt das ehemaligen Masterobjekt in seine Aboliste auf.

[A2] Ein Masterobjekt will die Kontrolle abgeben.

In diesem Fall sendet das Masterobjekt an einen seiner Slaves ein REQ_REQ_OWNER Event und bittet damit darum, ein REQ_OWNER Event zu schicken. Der weitere Ablauf erfolgt wie unter [A1] beschrieben.

Durch Senden eines STATE = EXIT Events an ein abonniertes Objekt wird das entsprechende Slaveobjekt gelöscht und das Abonnement aufgehoben. Dabei wird durch das Slaveobjekt folgendes sichergestellt:

[B1]

Das Slaveobjekt sendet ein UNSUBSCRIBE Event an seinen Abomaster.

[B2]

Wenn das Slaveobjekt selbst Abonnenten besitzt, dann müssen die Abonnenten von der bevorstehenden Löschung des Objektes informiert werden. Deshalb sendet das Objekt seine master_id (die ObjektID des Abomasterobjektes) als MASTER_ID = <id> Event an alle seine Abonnenten. Die Abonnenten senden dann ein SUBSCRIBE Event an den neuen Abomaster. Damit wird die Unterbrechung evtl. bestehender Aboketten verhindert.

[B3]

Ein Masterobjekt kann nur dann gelöscht werden, wenn es keine Abonnenten besitzt. Ein Masterobjekt mit Abonnenten wandelt sich nach dem Empfang eines STATE = EXIT Events selbständig in ein Slaveobjekt um.
Dabei geht die Objektkontrolle vom Masterobjekt an ein Slaveobjekt der gleichen Abonnementgruppe über.

4.8

Objektimplementation in Voodie

 

Da das Voodie System in C++ implementiert wurde, sind systemintern prinzipiell alle Module und die meisten Datenstrukturen C++ Klassen. In der Nutzersicht auf das Voodie System sind Objekte dagegen eigenständig agierende Einheiten, die sich durch Senden von Events an das Rendermodul darstellen können. Diese Einheiten, im folgenden Voodie Objekte genannt, können als Objektgruppen auf verschiedenen Stationen residieren. Die Voodie Objekte einer Gruppe synchronisieren sich dabei über den vorgestellten Mechanismus (Abonnement, Updates etc.).

Implementationsseitig besitzen Voodie Objekte eine Funktion, die Events behandeln kann. Dabei kann nötigenfalls die Eventbehandlungsfunktion der jeweils übergeordneten Basisklasse aufgerufen werden, um allgemeinere Events automatisch behandeln zu lassen.

In der vorliegenden Implementation können die meisten Events durch die Eventbehandlungsroutine der Basisklasse voodie_base_object_c behandelt werden. Dies betrifft insbesondere alle Events, die für die Mechanismen (Objektsubscription, Übergabe der Objektkontrolle usw.) notwendig sind. Objekte abgeleiteter Klassen behandeln nur die Events, die in den Basisklassen nicht behandelt werden können, bzw. die nur für das jeweilige Objekt relevant sind.

Die Klasse voodie_threaded_object_c und davon abgeleitete Klassen definieren Objekte, die eine Funktion zur Steuerung des Objektverhaltens besitzen. Diese Funktion läuft in einem separaten Thread (also parallel zum Rest der Applikation und anderen Thread-Funktionen) ab. In AVIARY (ab Seite 25 und /SNO94/) werden lightweight objects vorgeschlagen. Objekte mit Thread-Funktion können ebenfalls als leichtgewichtige autonome Objekte in diesem Sinne angesehen werden.

Die Implementation eines Voodie Objektes kann dann so erfolgen, als ob keine anderen Aktionen ausgeführt werden müßten. Dies vereinfacht die Implementation der Voodie Objekte sehr stark. Die Eventbehandlungsroutine läuft asynchron zur Thread-Funktion. Konkurrierende Datenzugriffe müssen dabei durch den Einsatz einer (standardmäßig vorhandenen) Mutexvariable synchronisiert werden.

Soll z.B. ein Voodie Objekt implementiert werden, welches einen Ball simuliert, so könnte die Implementation im Pseudocode etwa so aussehen:

Simulationsschleife [thread_function()]:

durchlaufe, solange du lebst:

wenn du Master bist: berechne Position, Flugrichtung, Geschwindigkeit, Beschleunigung mit Hilfe der vorherigen Werte, beachte dabei Umwelteinflüsse (Gravitation etc.) und andere Objekte (Kollisionen) benachrichtige alle Deine Abonnenten von den neuen Werten [update_slaves("<all_the_values>");] wenn du Slave bist: mache gar nichts wenn dein Status EXIT ist, begehe Selbstmord [suicide()] generiere in jedem Fall ein Event für das Ausgabemodul [enqueue_a_render_event ("Display me and use <all_the_values>");]

Diese Art der Implementation bedeutet, daß einzig das Masterobjekt Simulationsberechnungen ausführt. Das Verhalten der Slaveobjekte wird nur durch UPDATE Events vom Masterobjekt beeinflußt.

Es ist leicht einzusehen, daß dadurch ein sehr starker Kommunikationsaufwand durch die Master-Slave Synchronisation entsteht. Eine etwas andere Implementation löst dieses Problem dadurch, daß auch die Slaveobjekte ihr Verhalten berechnen. Im Pseudocode also so:

durchlaufe solange du lebst: 
    wenn du Master bist: 
        berechne Position,
                 Flugrichtung,
                 Geschwindigkeit,
                 Beschleunigung
            mit Hilfe der vorherigen Werte,
            beachte dabei Umwelteinflüsse (Gravitation etc.) und
                          andere Objekte (Kollisionen)
        wenn Interaktionen mit anderen Objekten aufgetreten sind.

benachrichtige alle Deine Abonnenten von den neuen Werten, [update_slaves("<all_the_values>");] wenn du Slave bist: berechne Position, Flugrichtung, Geschwindigkeit, Beschleunigung mit Hilfe der vorherigen Werte, beachte dabei Umwelteinflüsse (Gravitation etc.) und andere Objekte (Kollisionen) wenn dein Status EXIT ist, begehe Selbstmord [suicide()] generiere in jedem Fall ein Event für das Ausgabemodul [enqueue_a_render_event ("Display me and use <all_the_values>");]

Eventbehandlungsroutine [handle_event(event)]:

durchlaufe, wenn ein Event vorliegt: 
    lasse die Basisklasse(n) alle Events behandeln,
        die dort behandelt werden können
    behandle unbehandelte Ereignisse wie folgt:
        Event ist Update-event und du bist Slave:
              setze Deine Werte auf die Werte aus
              dem Update Event
              
              benachrichtige auch alle Deine Abonnenten
              von den neuen Werten 
               [update_slaves("<all_the_values>");]

ansonsten: das Event kann nicht behandelt werden.

4.8.1

Klassenbeschreibung

 

Bei der praktischen Implementierung der Voodie Objekte bietet sich die Aufstellung einer Klassenhierarchie an. Basis dieser Hierarchie bildet eine Klasse, deren Instanzen alle grundlegenden Eigenschaften eines Voodie Objektes besitzen. Von dieser Klasse werden weitere, spezialisierte Klassen abgeleitet. Abbildung 12 stellt den Zusammenhang der Klassen in der Hierarchie dar.

Abbildung 12: Klassenhierarchie

Im folgenden werden die einzelnen Klassen genauer beschrieben.

voodie_ base_ object_c

Voodie_base_object_c ist die Basisklasse für alle Objekte. Objekte dieser Klasse besitzen folgende öffentliche Attribute:

 

C++ Code Beschreibung
object_id_c _my_id; Objektidentifizierung des Objektes
char _class_name[100]; Name der Klasse des Objektes
bool _subscribable; Wenn diese Variable auf FALSE gesetzt wird, kann das Objekt nicht abonniert werden
object_id_c _master_id; Diese ObjektID ist die Identifizierung des Abomasterobjektes
object_state_c _state; Der Status des Objektes kann MASTER, SLAVE oder EXIT sein.
id_list_t _slave_objects; Eine Liste, in die ObjektIDs der Abonnenten stehen.

Alle Objekte dieser und abgeleiteter Klassen besitzen folgende öffentliche Funktionen:

C++ Code Beschreibung
voodie_base_object_c (int id); Konstruktor für das Objekt.
virtual ~voodie_base_object_c; Destruktor für das Objekt.
virtual int handle_event (event_c event); Diese Routine besorgt die Eventbehandlung.
virtual void update_slaves
(const char* update_string);
... sendet den übergebenen String als UPDATE Event an alle Abonnenten.

Objekte der Klasse voodie_base_object_c (und Objekte aller abgeleiteten Klassen) sind in der Lage, auf folgende Events zu reagieren:

		STATE = EXIT
		SEND_OI
		REQ_UPDATE ID = <slave_id>
		SUBSCRIBE ID = <slave_id>
		UNSUBSCRIBE ID = <slave_id>
  als Masterobjekt:                als Slaveobjekt:
   STATE = SLAVE                    STATE= MASTER
   REQ_OWNER ID = <slave_id>  MASTER_ID = <new_master_id>
   SET_OWNER ID = <old_master_id> REQ_REQ_OWNER
	  
voodie_ threaded_ object_c

Die Klasse voodie_threaded_object_c implementiert die Funktionalitäten, die ein Objekt mindestens besitzen muß, wenn seine thread_function() in einem separaten, unabhängigen Thread laufen soll. Dieser separate Thread dient der Implementation des Objektverhaltens und wird mit Objekt-Thread bezeichnet.

Diese Klasse ist von voodie_base_object_c abgeleitet. Folgende Attribute sind zusätzlich vorhanden:

C++ Code Beschreibung
pthread_mutex_t *_mutex; diese Mutex wird vom Objekt benutzt, um konkurrierende Zugriffe auf interne Variablen durch die Thread Funktion und die Eventbehandlungsfunktion zu synchronisieren
pthread_t _object_thread; Datenstruktur für Threaddaten

voodie_threaded_object_c besitzt folgende öffentliche Funktionen:

C++ Code Beschreibung
virtual void run (void); generiert Thread und startet thread_function()
virtual void thread_function (void); Diese Funktion kann von abgeleiteten Klassen überladen werden, um das Verhalten des Objektes zu implementieren.
voodie_ oi_ object_c

Die Klasse, deren Instanzen OI-Objekte sind, heißt voodie_oi_object_c. Diese Klasse ist von voodie_threaded_object_c abgeleitet. Auf jeder Station muß ein solches OI-Objekte vorhanden sein. Das OI-Objekt besitzt in der jetzigen Implementation die ObjektID 1. Das OI-Objekt hat die Aufgabe, eingehende OI Events in eine Liste einzutragen und regelmäßig zu prüfen, ob die Objekte noch immer existieren. Zusätzlich muß das OI-Objekt Events der FormSUBSCRIBE OI = <num> verarbeiten können (also entsprechende Abonnentenobjekte generieren).
OI-Objekte selbst können nicht abonniert werden, d.h. die Membervariable subscribable wird bei der Erzeugung des OI-Objektes explizit auf FALSE gesetzt.
Neben den Attributen der Basisklassen verfügt dieses Objekt zusätzlich über eine OI-Liste oi_list_t _oi_list.

Die Klasse redefiniert die Thread-Funktion und die Eventbehandlungsfunktion der Basisklasse voodie_threaded_object_c.

Objekte der Klasse voodie_oi_object_c sind in der Lage, auf folgende Events zu reagieren:

		OI ID = <id> CLASS = <class_name> STATE = <state_val>
		SUBSCRIBE OI = <num>
                SHOW_LIST
	  

Alle anderen Events werden durch die Basisklassen bearbeitet. Dazu genügt es, voodie_threaded_object_c::handle_event()vor der eigentlichen Eventbehandlung durch voodie_oi_object_c aufzurufen.

voodie_ nonthreaded_ object_c

Objekte dieser Klasse besitzen lediglich eine Funktion zur Ereignisbehandlung. Ein Thread-Funktion ist nicht vorhanden. voodie_nonthreaded_object_c kann als Basisklasse für Objekte dienen, die kein eigenes Verhalten besitzen (z.B. statische Umgebungsobjekte). Es ist denkbar, daß sehr viele Objekte einer virtuellen Umgebung solche statischen Objekte sind, da die meisten Gegenstände ihr Verhalten nicht eigenständig ändern müssen. Verhaltensänderungen können bei Objekten dieser Klasse über Ereignisse ausgelöst werden.

voodie_ first_ object_c

Voodie_first_object_c bildet die erste Beispielimplementation für eine Klasse, deren Instanzen echte Voodie Objekte sind. Diese Klasse ist von voodie_threaded_object_c abgeleitet.

Mit voodie_first_object_c wurden Mechanismen, die der Reduktion des Synchronisationsaufwandes dienen können, implementiert. Objekte dieser Klasse besitzen als Stellvertreter für echtes Verhalten eine Variable, die bei jedem Simulationsschritt um eins erhöht wird. Im einfachsten Fall erhöht lediglich das Masterobjekt diese Variable und benachrichtigt den Rest der Objektgruppe davon. Die jetzige Implementierung sieht allerdings vor, daß auch die Slaveobjekte diese Variable verändern können. Das Masterobjekt sendet nicht nach jeder Veränderung eine Synchronisationsnachricht, sondern nur in bestimmten Abständen. Die Slaveobjekte verändern die Variable eigenständig und gleichen den Wert der Variable mit dem Masterobjekt ab, wenn eine Synchronisationsnachricht ankommt. Durch diese Vorgehensweise kann auch Dead Reckoning implementiert werden.
Die Thread-Funktion dieser Klasse sieht im Pseudocode so aus:

	    while (!suiceded) {
              lock_mutex()
                enqueue_a_render_event ("message for RENDERER:
                             Display me and my Attributes");
                if (_state == MASTER) 
                  i++
              release_mutex()
              if (0 == (i%25))
                update_slaves("i is <value_of_i>");
              if (_state == SLAVE)
                i++
              if (_state == EXIT)
                suicide()
              wait_a_few_moments()
           }
	  

Die Eventbehandlungsfunktion sieht so aus:

           // Alle Events, die die Basisklassen behandeln
           // können, behandeln
           lock_mutex()
           handle_status = voodie_threaded_object_c::handle_event(event);
           if (EVENT_UNHANDLED == handle_status) {
             if (event ==  REQ_UPDATE ID = <slave_id>) {
               send_update_to_one_slave(slave_id, "i is <value_of_i>")
               handle_status = EVENT_HANDLED
             }
           if (_state == SLAVE) &&
              (event == "UPDATE i is <value_of_i>") {
             i = <value_of_i>
             set_attributes_on_update_event()
             update_slaves("i is <value_of_i>")
             handle_status = EVENT_HANDLED
           }
         }
         release_mutex()
         return (handle_status)
	  

voodie_first_object_c ist also in der Lage, die Events

          REQ_UPDATE ID = <slave_id>
          UPDATE i is <value_of_i>
	  

zu behandeln. Alle anderen Events werden durch die Basisklassen bearbeitet.

4.9

Funktionsbeschreibung des Prototypen

 

Abbildung 13: Prototyp mit Ereignismenu

Nachdem der Prototyp gestartet wurde, ist es möglich, verschiedene Ereignisse an die Verwaltungsmodule bzw. Objekte des Prototyp zu senden, und damit die Mechanismen zu testen. Die Ereignisse werden durch die Auswahl aus einem Menü erzeugt. Abbildung 13 zeigt den Prototypen mit aufgeklapptem Ereignismenü.

Es können Objekte der Klassen

voodie_first_object_c
voodie_threaded_object_c
voodie_nonthreaded_object_c

generiert werden.

Es ist weiterhin möglich, von einer anderen Station, auf der auch der Prototyp läuft, die OI der dort vorhandenen Objekte anzufordern. Nach der Auslösung eines entsprechenden Ereignisses (SEND_ALL_OI Event) durch die Anwahl des Menüpunktes

Events | Request All OI from ...

erhält das OI-Verwaltungsobjekt (ObjektID = 1) die OI der entsprechenden Objekte und stellt diese in einer Liste dar (Abbildung 14).

Abbildung 14:  Prototyp, OI-Objekt (Objekt id = 1) mit OI-Liste

Das Abonnement dieser Objekte erfolgt dadurch, daß dem OI-Objekt entsprechende SUBSCRIBE OI Events zugesandt werden. Die Übergabe der Objektkontrolle von einem Objekt einer Objektgruppe zu einem anderen, kann getestet werden, indem eine Objektgruppe erzeugt wird und dem Masterobjekt ein STATE = EXIT Event geschickt wird. Das Masterobjekt gibt dann die Kontrolle ab, weil es davon ausgeht, demnächst gelöscht zu werden.

Der Prototyp generiert eine Protokolldatei. In dieser Protokolldatei werden die Aktivitäten des Programmes und Debug Informationen festgehalten. Der Umfang der zu protokollierenden Daten ist dabei über die Kommandozeile einstellbar.




mm
letzte Änderung: 05.05.1999, marko[at]netz-meister[punkt]de