3 - Aufgabe 6: Ereignisbearbeitung und Synchronisation [ID:36128]
50 von 86 angezeigt

Bis jetzt konnten wir in unseren Benutzeranwendungen eine Synchronisation nur durch aktives Warten

oder Betreten der Epilog-Ebene erreichen, was wir so beispielsweise für die Ausgabe

verwendet haben.

In dieser Aufgabe führen wir Synchronisationsobjekte ein, wodurch die Anwendungen sich nun gegenseitig

über Ereignisse informieren bzw. passiv darauf warten können.

Die Ausgabe kann nun mittels Semaphoren synchronisiert werden.

Außerdem bekommen die Threads die Möglichkeit, sich für eine bestimmte Zeit schlafen zu legen.

Anschaulich bzw. eher anhörlich lässt sich das mittels dem PC Speaker demonstrieren,

indem man nacheinander verschiedene Töne abspielt, also beim Pit mittels Pulsdauermodulation

eine bestimmte Frequenz für eine gewisse Zeit einstellt und sich daraus dann eine Melodie ergibt.

Zugegeben, der piepsende Systemlautsprecher ist aufs guten Grund nur noch ein historisches Relikt

und hat seit Jahrzehnten dank der standardmäßig integrierten Soundkarten keinerlei Relevanz mehr.

Aber vor 30 Jahren wurde das insbesondere bei Spielen intensiv und durchaus sehr kreativ genutzt.

Und uns kann es beim Erkennen von fehlerhaften Implementierungen helfen.

Die Umsetzung beginnen wir mit dem Zimmer vorn. Neben der Ausgabe soll auch die Eingabe darüber synchronisiert werden.

Mittels Get-Key kann ein Thread die nächste gedrückte Taste bekommen.

Sofern alle vorherigen Tasten bereits abgerufen wurden, wird auf den nächsten Tastendruck gewartet.

Ein solches Warten soll auch zeitgesteuert möglich sein.

Wer will, kann dies mittels dem gezeigtem PC Speaker testen.

Ein kurzer Beispielcode dafür ist in der Angabe gelistet.

Damit müssen wir uns nun gegen ein neues Problem wappnen.

Wenn gerade alle Threads schlafen, was soll denn dann ausgeführt werden?

In solchen Fällen müssen wir uns um den Leerlauf des Prozesses kümmern.

Und wer will, kann dabei auch stups zu einem Tickless-Körnerl umbauen.

Damit die Benutzeranwendungen bequem die neue Funktionalität verwenden können,

wollen wir sie in Systemaufrufsschnittstellen kapseln, wie wir das bereits mit dem Guarded Scheduler getan haben.

Konkret betrifft dies folglich die Tastatur, Semaphore sowie das zeitgesteuerte Schlafen.

Sowohl die Semaphore als auch die Bell, die das zeitgesteuerte Schlafen eines Threads umsetzt,

werden beide von Waiting Room abgeleitet, welche wiederum lediglich eine Queue vom wartenden Threads implementiert.

Für Semaphoren ist dies dabei offensichtlicher, dass wir hier potentiell mehrere wartende Threads verwalten müssen.

Bei der Bell hingegen erscheint das am Anfang etwas unnötig, da dieses Objekt nur für einen einzelnen Thread existiert,

eben der sich gerade schlafen legen will.

Allerdings spart uns die Verwendung der gemeinsamen Basis-Klasse Waiting Room einiges an doppeltem Code,

insbesondere im Scheduler, welcher sich nun auch mit dem neuen Zustand wartend rumschlagen muss.

Dass wir zum Synchronisieren über Threads hinweg gemeinsame Semaphore-Objekte brauchen und diese somit eher statisch allokieren, dürfte kaum überraschen.

Aber der Einsatz der Bell, dem Wecker, dürfte noch etwas unklar sein.

Eine Bell kann auch dynamisch erstellt werden, als temporäres Objekt auf dem Stack des Threads,

der sich damit selbst für eine gewisse Zeit schlafen legen will.

Alle aktiven Wecker-Objekte werden vom Bell-Ringer, zu Deutsch dem Glockner, in einer verketteten Liste verwaltet,

welcher regelmäßig prüft, ob deren Zeit schon fertig abgelaufen ist, und sie dann gegebenfalls loitet,

also die ausgeschlafenen Threads wieder aufweckt, indem er sie in die Ready-Liste des Schedulars eintritt.

Angestoßen wird diese Prüfung natürlich durch den Lapig-Timer, welcher so eingestellt sein sollte, dass er im Millisekundentakt eine Unterbrechung auslöst.

Es ist dabei ausreichend, wenn der Bell-Ringer nur auf einem Kern ausgeführt wird, beispielsweise dem Bootstrap-Prozessor.

Wie bereits erwähnt, kann es nun sehr leicht vorkommen, dass unsere Threads alle schlafen oder auf einen Semmler vorwarten,

also nicht bereit sind und somit die Ready-Liste des Schedulars leer ist.

Was soll dann ausgeführt werden?

Wir brauchen einen speziellen Leerlauf-Thread, der sich am besten selbst verdrängt, sobald wieder ein Thread bereit ist,

also die Ready-Liste des Schedulars nicht mehr leer ist.

Und ha genau das macht dieser Code.

Leider in einer Endlosschleife, es wird dauernd aktiv auf eine Änderung der Bereitschaftsliste geprüft,

Teil einer Videoserie :
Teil eines Kapitels:
Ereignisbearbeitung und Synchronisation

Zugänglich über

Offener Zugang

Dauer

00:08:31 Min

Aufnahmedatum

2020-08-25

Hochgeladen am

2021-09-20 19:16:24

Sprache

de-DE

Tags

betriebssysteme synchronisation operating systems stubs
Einbetten
Wordpress FAU Plugin
iFrame
Teilen