Real Time Specification for Java

Echtzeitfähigkeit mit Java auf Systemen mit geringen Ressourcen

Seite: 3/3

Anbieter zum Thema

Direkter Zugriff auf Speicher und Register

Echtzeitsysteme benötigen teilweise einen direkten Zugriff auf Speicher und Register, was mit Standard Java nicht möglich ist. Die RTSJ stellt hierfür die Klasse RawMemoryAccess mit der Unterklasse RawMemoryFloatAccess zur Verfügung.

Durch die Klasse RawMemoryAccess kann ein Speicherbereich, der durch eine Startadresse (Offset) und eine Größenangabe (Size) fest definiert ist, für den direkten Zugriff freigegeben werden. Der definierte Speicherbereich wird je nach Größe als byte, short, int oder long interpretiert. Mehrere Speicherbereiche hintereinander können als Array dieser Datentypen angesprochen werden.

Die Klasse RawMemoryFloatAccess nutzt den gleichen Mechanismus, interpretiert die Speicherbereiche allerdings mit den Datentypen float oder double. Bei direktem Speicherzugriff sind drei Punkte zu beachten:

  • Die Reihenfolge der Bytes ist plattformabhängig (Byte Order) und muss richtig interpretiert werden.
  • In diesen Speicherbereichen dürfen keine Objekte angelegt werden.
  • Nur der direkte Zugriff auf Speicherbereiche außerhalb der VM ist erlaubt, um Inkonsistenzen zu vermeiden.

Scheduling im Echtzeitbetriebssystem

Ein wichtiger Punkt für Echtzeitsysteme ist das Scheduling. Standard Java benutzt einen nicht ganz konsequenten Prioritätsscheduler mit wenigen Prioritätsstufen. Deshalb führt die RTSJ die Klasse Scheduler ein. Hier kann ein eigener Scheduler implementiert werden oder es kann der nach RTSJ zwingend vorhandene PriorityScheduler eingesetzt werden.

Dieser arbeitet nach dem gängigsten Algorithmus und führt ein Fixed Priority Preemptive Scheduling durch. Jeder Thread bekommt eine Priorität zugewiesen. Dabei bekommt der Thread mit der höchsten Priorität die CPU. Aktuell ausgeführte Threads mit niedriger Priorität werden unterbrochen.

Auch die Prioritätsstufe des JGC kann eingestellt werden. Der Scheduler ist als Singleton implementiert. Dadurch werden Inkonsistenzen und ein nicht vorhersagbares Zeitverhalten vermieden, da nicht mehrere Scheduler gleichzeitig aktiv sein können. Die RTSJ schreibt mindestens 38 unterschiedliche Prioritätsstufen zu. Manche VMs implementieren mehr Stufen. Dabei muss beim Wechsel oder Update einer VM darauf geachtet werden, dass noch alle Prioritäten stimmen, vor allem beim Arbeiten mit den Methoden getMaxPriority() und getMinPriority().

Threads ein exaktes Zeitverhalten mitgeben

Um den Threads ein exaktes Zeitverhalten zu geben, wird das Java Interface Runnable um das Interface Schedulable erweitert. Neben den SchedulingParameters werden ProcessingGroupParameters, ReleaseParameters und MemoryParameters definiert. Da eine Auflistung und Erklärung sämtlicher Parameter jeden Rahmen sprengen würde, soll hier nur auf die RTSJ verwiesen werden. Es sei erwähnt, dass diese Parameter ein System hochflexibel konfigurieren lassen.

Passend zum Echtzeitscheduler sind zwei weitere Threadklassen spezifiziert, die von der Klasse Thread abgeleitet sind. Der RealtimeThread nutzt das Interface Schedulable. Für den RealtimeThread kann ein Zeitverhalten definiert werden. Dieses wird allerdings nicht zwingend eingehalten, da dieser Threadtyp auch mit dem HeapMemory arbeiten darf. Der HeapMemory wird vom JGC überwacht. Nach Aktivierung des JGCs muss auf dessen Ende gewartet werden, um Inkonsistenzen zu vermeiden. Dies verzögert auch den erneuten Aufruf von RealtimeThread. In Anbetracht der genannten Punkte ist die Klasse nur für weiche Echtzeitanforderungen einzusetzen, in der Zeitvorgaben nicht zwingend eingehalten werden müssen.

Für harte Echtzeitbedingungen gibt es eine Ableitung von RealtimeThread: den NoHeapRealtimeThread. Dieser verwendet kein HeapMemory und unterbricht einen laufenden JGC. Zum Datenaustausch zwischen den unterschiedlichen Threads werden verschiedene Queues verwendet. Eine WaitFreeWriteQueue kann ohne Verzögerung beschrieben, aber nur synchronisiert gelesen werden.

Eine WaitFreeReadQueue funktioniert genau umgekehrt und besteht aus beiden oben genannten Queues. Allerdings wird sie in der RTSJ als veraltet gekennzeichnet, da sie durch eine WaitFreeWriteQueue und eine WaitFreeReadQueue abgebildet werden kann. Ein Echtzeit Thread muss immer auf der unsynchronisierten Seite mit Sofortzugriff auf die Daten implementiert werden.

Threads mit unterschiedlichen Prioritäten

Threads mit unterschiedlichen Prioritäten benötigen oft Zugriff auf die gleichen exklusiven Ressourcen, zum Beispiel Hardware oder Queues. Zur Synchronisation dieser Ressourcen wurde die abstrakte Klasse MonitorControl spezifiziert. Diese verfügt über zwei Mechanismen um zu verhindern, dass Threads mit hoher Priorität beim Zugriff auf exklusive Ressourcen auf Threads mit niedriger Priorität warten müssen.

Die erste Strategie nennt sich PriorityInheritance. Hierbei wird einem Thread, der eine exklusive Ressource nutzt, die Priorität des höchsten wartenden Threads zugewiesen. Für die zweite Strategie, PriorityCeilingEmulation, vergibt man der Ressource eine Priorität. Diese wird dem aktuell zugreifenden Thread temporär zugewiesen.

Die letzte verbleibende Hürde für Echtzeitfähigkeit und Embedded Systems ist die Asynchronität. Zyklische Aufgaben müssen bei bestimmten Events unterbrochen werden, um sofort reagieren zu können. Für diese Aufgabe werden AsyncEventHandler genutzt. Sie werden an ein bestimmtes Ereignis geknüpft und beim Auftreten des Ereignisses ausgelöst. Dabei können mehrere AsyncEventHandler an ein Ereignis geknüpft werden. Der AsyncEventHandler stellt sicher, dass selbst bei mehrmaligem Auslösen eines Ereignisses die Handler Methode nur einmal aufgerufen wird und kapselt damit die eigentliche Reaktion. Sollten sehr schnelle Reaktionen benötigt werden, muss auf den BoundAsyncEventHandler zurückgegriffen werden. Dieser wird nicht erst, wie der AsyncEventHandler , beim Auftritt des Ereignisses dynamisch vorbereitet, sondern kann sofort starten. Dieses Verhalten geht dafür auf Kosten der Ressourcen.

Der letzte erwähnenswerte Punkt ist die AsynchronousInterruptedException. Sie wird genutzt, um das Zeitverhalten auch bei rekursiven Algorithmen zu gewährleisten, indem der Algorithmus zu einem bestimmten Event oder nach einer bestimmten Laufzeit unterbrochen werden kann.

Bei Betrachtung all dieser Erweiterungen durch die RTSJ kann Java für Entwickler von Echtzeit- und Embedded Systemen durchaus interessant werden. Der nächste Artikel soll deshalb einige auf dem Markt befindliche VMs für die RTSJ vorstellen.

//heh

* * Stefan Kuntschar ... ist Softwareentwickler bei Mixed Mode in München.

(ID:26657820)