Im ersten Teil dieses Tutorials wurden gemeinsame Ressourcen mithilfe eines Semaphors erfolgreich geschützt. Dadurch konnte verhindert werden, dass mehrere Tasks gleichzeitig auf die serielle Schnittstelle zugreifen. Synchronisation löst jedoch nicht automatisch alle Probleme paralleler Systeme. Sobald mehrere Ressourcen gleichzeitig benötigt werden, können neue Fehlerbilder entstehen. Besonders kritisch sind Situationen, in denen sich Tasks gegenseitig blockieren und keine der beteiligten Aufgaben ihre Arbeit fortsetzen kann. Dieses Problem bezeichnet man als Verklemmung oder Deadlock.
Deadlocks treten in der Praxis häufiger auf, als zunächst vermutet wird. Bereits einfache Embedded-Anwendungen verwenden oft mehrere gemeinsam genutzte Ressourcen gleichzeitig, beispielsweise: Sensoren, Kommunikationsschnittstellen, Speicherzugriffe, Dateien, oder Peripheriegeräte. Werden diese Ressourcen in unterschiedlicher Reihenfolge angefordert, kann es passieren, dass jeder Task bereits eine Ressource besitzt und gleichzeitig auf eine weitere wartet. Dadurch entsteht ein zyklisches Warten, aus dem keiner der Tasks selbstständig herauskommt.
Zielsetzung
Nach Abschluss dieses Abschnitts sollen die Studierenden:
In parallelen Systemen benötigen Tasks häufig nicht nur eine einzelne Ressource, sondern mehrere Ressourcen gleichzeitig. Beispiele dafür sind: mehrere Sensoren, verschiedene Kommunikationsschnittstellen, Speicher und Dateioperationen, oder unterschiedliche Hardware-Komponenten. Damit ein Task seine Arbeit ausführen kann, müssen alle benötigten Ressourcen verfügbar sein.
Im folgenden Beispiel werden zwei Ressourcen verwendet:
eine Bohrmaschine
ein Bohrer
Erst wenn beide Ressourcen verfügbar sind, kann ein Loch in die Wand gebohrt werden.
Ablauf ohne Deadlock
Fordern alle Tasks die Ressourcen immer in derselben Reihenfolge an, funktioniert das System problemlos.
zuerst Bohrmaschine reservieren
danach Bohrer reservieren
Loch bohren
beide Ressourcen freigeben
Da beide Tasks dieselbe Reihenfolge verwenden, entsteht keine gegenseitige Blockierung.
Deadlock (Verklemmung)
Ein Deadlock entsteht, wenn mehrere Tasks dauerhaft aufeinander warten. Im Bohrer-Beispiel entsteht dies durch unterschiedliche Zugriffsreihenfolgen.
Task A
reserviert Bohrmaschine
wartet auf Bohrer
Task B
reserviert Bohrer
wartet auf Bohrmaschine
Nun besitzt jeder Task bereits eine Ressource und wartet gleichzeitig auf die jeweils andere Ressource.
Zyklisches Warten
Keiner der beiden Tasks kann fortfahren:
Task A gibt die Bohrmaschine nicht frei, solange der Bohrer fehlt.
Task B gibt den Bohrer nicht frei, solange die Bohrmaschine fehlt.
Das System befindet sich nun in einer dauerhaften Blockierung. Dieses Verhalten bezeichnet man als: Deadlock oder Verklemmung
Eigenschaften eines Deadlocks
Ein Deadlock besitzt typischerweise vier Bedingungen:
Sind alle vier Bedingungen erfüllt, kann ein Deadlock entstehen.
Erkennen eines Deadlocks
Ein Deadlock zeigt sich häufig dadurch, dass: Tasks scheinbar „einfrieren“, keine neue Ausgabe mehr erscheint, LEDs nicht mehr reagieren, oder das System nicht mehr weiterarbeitet. Besonders problematisch ist, dass solche Fehler oft nur selten auftreten und schwer reproduzierbar sind. In Embedded-Systemen können Deadlocks kritische Folgen haben: Kommunikationsabbrüche, blockierte Steuerungen, eingefrorene Benutzeroberflächen, oder komplette Systemausfälle.
Vermeidung von Deadlocks
Eine der wichtigsten Strategien zur Vermeidung von Deadlocks ist eine feste Reihenfolge beim Zugriff auf Ressourcen. Alle Tasks müssen Ressourcen immer identisch anfordern:
zuerst Bohrmaschine, danach Bohrer.
Dadurch kann kein zyklisches Warten entstehen. Weitere Strategien sind: Zeitüberschreitungen (Timeouts), zentrale Ressourcenverwaltung, Vermeidung unnötiger Ressourcensperren, möglichst kurze kritische Abschnitte
In einem ersten Versuch werden wir beide Tasks die Ressourcen in der gleichen Reihenfolge anfordern lassen und die Ausgabe auf dem seriellen Monitor beobachten.
Nun werden wir in Task 2 die Reihenfolge der Ressourcen ändern, also Bohrer- und Bohrmaschinenzugriff vertauschen. Das Resultat ist abhängig vom Timing, d.h. wann welcher Task tatsächlich zum laufen kommt. Aber schon nach kurzer Zeit stellt sich ein Deadlock ein. Die beiden Tasks blockieren sich gegenseitig, jeder wartet auf die Freigabe der Ressource durch den anderen.
Mit zunehmender Komplexität moderner Embedded-Systeme steigt auch die Anzahl paralleler Prozesse. Dadurch wächst die Gefahr von Synchronisationsproblemen erheblich.
Das Verständnis von:
ist deshalb eine grundlegende Voraussetzung für die Entwicklung stabiler und zuverlässiger IoT- und Embedded-Anwendungen.
FreeRTOSTM is a trademark of Amazon.com, Inc. or its affiliates.
Sie verlassen die offizielle Website der Hochschule Trier