Inhalte zur Vorlesungswoche #12, Entwicklung fehlertoleranter Software für eingebettete Echtzeitsysteme im Wintersemester 2024/25
(EN google-translate)
(PL google-translate)
Beschäftigung im Falle einer Verspätung:
|
Themen heute:
|
Zu Beginn der Lehrveranstaltung, jaetzt, in der zweiten Hälfte des Semesters, werden Themen vertieft, die Sie bei der Bewältigung Ihrer Projektarbeit unterstützen können.
1 Callback-Funktionen
Sie müssen mit Callback-Funktionen umgehen. Ein genauerer Blick darauf sollte Ihnen mehr Sicherheit beim Umgang geben und ein Überblick über die vordefinierten Callback-Funktionen in Processing sollte Ihnen mehr Möglichkeiten für die Programmentwicklung eröffnen.
Eine Auswahl an vordefinierten Callback-Methoden in Java/Processing:
|
Man muss sich das so vorstellen, dass vereinbart ist, dass eine bestimmte Objektmethode, auf die der Anwendungsprogrammierer in der Regel keinen Zugriff hat, automatisch beim Auftreten bestimmter Ereignisse eine Call-Backmethode eines bestimmten Namens aufruft, wenn diese vom Anwendungsprogrammierer bereit gestellt wird. Das Auslösen des Aufrufs kann über einen Softwareinterrupt erfolgen, oder zyklisch über einen nebenläufigen Prozess (s.u.) geregelt sein.
Dabei ist wichtig, dass der Kopf dieser Methode (Name Case-sensitiv, Übergabeparameter, Rückgabeparameter) exakt mit der vereinbarten übereinstimmt, damit sie dann auch automatisch aufgerufen wird.
Im besten Fall kann der Anwendungsprogrammierer allgemein bestimmen, in welcher eigenen Klasse er die Callbackmethode unterbringt. In diesem Fall wird ein Objekt dieser Klasse bei dem fremden Aufrufer-Objekt registriert, beispielsweise, indem dem Konstruktor der fremden Klasse eine Referenz auf das eigene Objekt übergeben wird. Ein Beispiel dazu findet sich in der Klasse DoppelIMU, die auch in dem Projekt Taichinification von letzte Woche verwendet wurde:
import hypermedia.net.*;
public class DoppelIMU
{
...
//eigener Konstruktor:
public DoppelIMU(String ip, int port, int port2)
{
this.ip = ip;
this.port = port;
this.port2 = port2;
udp = new UDP( this, 6000 ); //Übergabe der Referenz auf das eigene Objekt mit "this"
udp.listen( true );
}
...
//Callback-Methode, die vom udp-Objekt aufgerufen wird:
public void receive( byte[] data, String ip, int port )
{
...
}
...
Code 0-1: Registrierung des eigenen Objekts bei dem UDP-Objekt.
Oft in Processing muss aber das Objekt mit der Callback-Methode vom Typ PApplet sein. Das ist die Basisklasse, von dem jedes Projekt bei Processing erbt und das das Überschreiben der Methoden setup() und draw() erlaubt.
In den Beispielen zu den Libraries finden Sie stets einfache Beispiele dazu, wie mit den jeweiligen Callbackmethoden umgegangen wird:
|
...aber auch auf den Referenz-Seiten von processing.org:
|
2 Nebenläufige Prozesse in Java
Nebenläufige Prozesse, so genannte Threads, bieten eine elegante Möglichkeit Codeelemente voneinander getrennt zu halten. So kann ein Faultobserver nebenläufig als paralleler Prozess laufen und bestimmte Vorgänge überwachen, ohne dass ein sichtbarer Aufruf in einem anderen Programmteil zu sehen ist. Jedoch können durch Zugriff auf die gleichen Ressourcen durch mehrere parallel laufende Prozesse auch Programmabläufe korrumpiert werden. Hier gilt es, Maßnahmen zu ergreifen, die das verhindern, wie beispielsweise Methoden mit dem Zusatz synchronized zu versehen.
Fähigkeiten der Klasse Thread: 36_Java/04_Threads
Gängige Methode zur Implementierung eigener nebenläufiger Prozesse (mit Schnittstelle Runnable): 77_Android/04_Threads
Verwendung des Modifikators synchronized: 67_Echtzeitsysteme/02_Threads/02_Synchronisierung
Im Unterricht werden noch einfache Programmbeispiele entwickelt werden und nachfolgend hochgeladen.
Beispiel zur Erzeugung eines eigenen nebenläufigen Prozesses
Neben meinProzess;
public void setup()
{
frameRate(5);
meinProzess = new Neben();
}
public void draw()
{
println("Hauptprozess");
}
public void keyPressed()
{
meinProzess.toggle();
}
Code 0-2: Haupttab -- Beispiel zur Erzeugung eines eigenen nebenläufigen Prozesses
public class Neben implements Runnable
{
boolean aktiv = false;
public Neben()
{
(new Thread(this)).start();
}
public void toggle()
{
aktiv = !aktiv;
println("jetzt aktiv=="+aktiv);
}
public void run()
{
while(true)
{
try
{
Thread.sleep(200);
}
catch(Exception e)
{
}
if(aktiv) println(".....nebenläufiger Prozess");
}
}
}
Code 0-3: Tab mit eigener Klasse -- Beispiel zur Erzeugung eines eigenen nebenläufigen Prozesses
Nutzung eines nebenläufigen Prozesses als Fault-Observer
Neben meinProzess;
public void setup()
{
frameRate(5);
meinProzess = new Neben();
}
boolean autopilot_running =false;
public synchronized void autopilot(boolean start)
{
autopilot_running = start;
println("Autopilot=="+autopilot_running);
}
public void draw()
{
println("Hauptprozess");
}
public void keyPressed()
{
meinProzess.update();
}
Code 0-4: Haupttab -- Nutzung eines nebenläufigen Prozesses als Fault-Observer
public class Neben implements Runnable
{
public Neben()
{
(new Thread(this)).start();
}
/**
wird von zyklischem Prozess aufgerufen, dient zum Überprüfen des Zeitintervalls in dem
der betreffende Prozess aufgerufen wird
*/
long T=System.currentTimeMillis();
public void update()
{
T=System.currentTimeMillis();
}
public void run()
{
while(true)
{
try
{
Thread.sleep(200);
}
catch(Exception e)
{
}
if(System.currentTimeMillis()-T>2000)
{
println("WARNUNG: Zeitüberschreitung");
autopilot(true);
}
}
}
}
Code 0-5: Tab mit eigener Klasse -- Nutzung eines nebenläufigen Prozesses als Fault-Observer
3 Fortsetzen der Projektarbeit
|