- Synchronisation mit Hilfe von Semaphoren und anderen Kernobjekten
OOStuBS/MPStuBS soll nun um Synchronisationsobjekte erweitert werden, mit denen Threads sich gegenseitig über verschiedene Ereignisse informieren bzw. auf Ereignisse warten können. Folgende Synchronisationsobjekte sollen in dieser Aufgabe erstellt werden:
- Mit Hilfe von Semaphoren besteht die Möglichkeit, Anwendungsprozesse miteinander zu synchronisieren. Darüberhinaus sollen sie dazu verwendet werden, Anwendungsprozesse bei der Tastaturabfrage zu blockieren, bis eine Taste gedrückt wurde.
- Durch Buzzer (Wecker) können Threads sich für eine bestimmte Zeit schlafen legen.
Hierzu müssen die Klassen Waitingroom, Semaphore, Customer, Organizer, Bell, Bellringer, Buzzer, Guarded_Buzzer, Guarded_Organizer, Guarded_Semaphore und Guarded_Keyboard implementiert, die Klasse Keyboard erweitert und die Klassen Thread sowie Watch angepasst werden.
Die Klasse Guarded_Scheduler wird nicht länger benötigt, da Guarded_Organizer ihre Aufgabe übernimmt. Ebenso soll das globale Guarded_Scheduler-Objekt scheduler durch ein globales Guarded_Organizer-Objekt organizer ersetzt werden.
Abschliessend soll dann noch eine Möglichkeit geschaffen werden, den Prozessor schlafen zu lassen, wenn keine Benutzerprozesse vorhanden sind.
In OOStuBS empfiehlt es sich dazu in einer Schleife den Idle-Befehl der CPU auszuführen. Neue Prozesse können lediglich durch Interruptbehandlungsroutinen aktiviert werden. Wenn nach einem Interrupt wieder neue Prozesse in der Bereitliste vorhanden sind, soll die Ausführung fortgeführt werden.
In MPStuBS ist die Idle-Problematik jedoch etwas komplexer, da sich hier eine Teilmenge der CPUs im Idle-Zustand befinden können können während andere CPUs noch Prozesse ausführen. Darum ist es hier sinnvoll mit dedizierten, pro Prozessor allokierten Idle-Threads (Instanzen der Klasse IdleThread) zu arbeiten, die eingeplant werden, sobald keine anderen Prozesse vorhanden sind. Die Idle-Threads führen dann ein Idle-Loop analog zu dem aus OOStuBS aus. Darüberhinaus ist es notwendig schlafende Prozessoren immer dann zu wecken, wenn ein Prozess durch Aufruf von Scheduler::ready() auf die Bereitliste gesetzt wird. Dazu soll ein eigener Interprozessorinterrupt (IPI) analog zur Implementierung von Scheduler::kill(Entrant& that) in Aufgabe 5 verwendet werden.
Klassenübersicht für Aufgabe 6
Beginnt am besten mit der Implementierung der Semaphoren. Dazu müssen zunächst die Klassen
Waitingroom,
Semaphore,
Customer,
Organizer,
Guarded_Organizer und
Guarded_Semaphore implementiert werden. Mit Hilfe von Semaphorvariablen solltet ihr nun verhindern können, dass sich eure Anwendungsprozesse bei der Bildschirmausgabe gegenseitig behindern.
Im nächsten Schritt könnt ihr dann die Klasse
Keyboard um die getkey()-Methode erweitern, durch die Prozesse nun mit Hilfe einer
Semaphore beim Lesen von der Tastatur blockieren, falls keine Taste gedrückt wurde. Erweitert euer Programm dahingehend, dass einer der Prozesse Tastaturabfragen vornimmt (und in irgendeiner sichtbaren Weise darauf reagiert).
Anschließend können die Klassen
Bell und
Bellringer implementiert und getestet werden. Von
Bellringer sollte eine globale Instanz
bellringer angelegt werden. Wenn klar ist, dass insbesondere der
Bellringer funktioniert, wie er sollte, könnt ihr die Klassen
Buzzer und
Guarded_Buzzer erstellen. Damit lassen sich nun sehr einfach periodische Prozesse erstellen, indem ein Prozess sich immer wieder für ein paar Millisekunden schlafen legt und dann z. B. eine Ausgabe macht. Auch dafür sollt ihr ein geeignetes Beispiel vorbereiten.
Wenn alle vorhergenden Klassen implementiert und getestet wurden, kann man nun die Idle-Problematik angehen und den entsprechnden Ansatz implementieren. Dies sollte auch getestet werden, indem man in der Testapplikation regelmäßig dafür sorgt, dass zuwenig (in MPStuBS) oder gar keine Prozesse zum Ausführen vorhanden sind.
Die Implementierung der Klasse
List haben wir bereits für euch erledigt.