Im letzten Teil hatten wir ein kleines Beispiel, in dem aktiv auf das Eintreffen eines Signals gewartet wird.
Da dies aber unnötig Rechenzeit verschwendet, wollen wir uns nun anschauen, wie man stattdessen passiv auf das Eintreffen eines Signals warten kann.
Dazu haben wir jetzt hier eine leicht modifizierte Variante des Programms, das wir eben hatten.
Wir haben hier wieder eine globale Variante, event, die wir nutzen, um das Eintreten eines Signals zu vermerken.
Und wir haben einen Signalhändler, der die Event-Variante, die initial auf Null gesetzt ist, auf den Wert 1 setzt.
Die Funktion waitForEvent, in der wir nun auf das Eintreffen eines Signals warten, wird um eine Pseudofunktion erweitert.
Nämlich haben wir nun in der wild-Schleife, in der jemals aktiv gewartet wurde, den Aufruf an eine Suspend-Funktion.
Von dieser nehmen wir nun an, dass sie nun so lange schläft, bis ein Signal eintritt. Sobald ein Signal eingetreten ist,
kehrt sie zurück und der Prozess kann seine Ausführung fortfahren.
Wie wir uns also vorstellen, dass dieses Programm funktionieren soll, ist, dass die Funktion waitForEvent aufgerufen wird
und dass so lange durch die wild-Schleife iteriert wird, bis früher oder später das richtige Signal aufgefangen wird
und die Variante event auf den Wert 1 gesetzt wird.
Und wie nun hier auf der Folie schon leicht suggeriert, müssen wir uns überlegen, ob ein Nebenläufigkeitsproblem auftreten kann.
Dazu müssen wir überlegen, an welchen Stellen das Signal alles eintreffen kann.
Nehmen wir nun einmal an, das Signal wird zugestellt, noch bevor die wild-Schleife betreten wird.
In dem Fall wird sofort die Variante event auf 1 gesetzt und wenn der Kontrollfluss an die Funktion waitForEvent zurückkehrt,
wird diese die Schleifenbedingungen prüfen und gar nicht erst in die Schleife springen.
Wenn wir nun weiter annehmen, dass das Signal auftritt, während die suspend-Funktion ausgeführt wird,
dann wissen wir, dass ab dem Moment die suspend-Funktion wieder zurückkehrt, wenn die Signalbehandlung abgeschlossen ist
und anschließend wird die Schleifenbedingungen erneut geprüft.
Falls das richtige Signal eingetreten ist und event auf 1 gesetzt wurde, wird auch hier wieder die Schleife abbrechen.
Worüber wir uns jetzt aber Gedanken machen müssen, ist, was passiert, wenn das Signal genau dann antrifft,
wenn die Schleifenbedingungen geprüft wurden, aber sich der Prozess noch nicht schlafen gelegt hat.
Wenn dies passiert, dann wurden erst die Schleifenbedingungen geprüft, während event noch 0 war.
Wenn anschließend das Signal auftritt, wird event auf 1 gesetzt.
Das bedeutet, das Ereignis, auf das wir warten, ist eingetreten.
Anschließend wird aber, sobald die Signalbehandlung wieder zurückkehrt, die suspend-Funktion aufgerufen
und ab dem Moment legt sich der Prozess schlafen und zwar solange, bis erneut ein Signal auftritt.
Wenn wir nun aber Pech haben, wird kein weiteres Signal mehr auftreten.
Ab dem Moment hat der Prozess das event verpasst und wird nicht mehr aufgeweckt.
Also werden wir nun versuchen, mit den Pseudofunktionen Block-Signal und Unblock-Signal das Eintreffen der Signale solange zu verzögern,
bis wir einmal die Schleifenbedingungen ausgewertet haben und uns schlafen gelegt haben.
Dazu schützen wir einmal die Auswertung der Schleifenbedingungen und geben, kurz bevor wir uns schlafen legen, die Signale wieder frei.
Würden wir die Signale nicht freigeben, würde die Suspendfunktionen sich schlafen legen und niemals aufgeweckt werden, da keine Signale zugestellt werden können.
Sobald die Suspendfunktion zurückgekehrt ist, werden die Signale wieder blockiert, damit die Schleifenbedingungen ausgewertet werden können.
Jetzt können wir mal überlegen, ob diese Art der Signalblockierung ausreichend ist und wir damit das Problem aus der Welt geschafft haben.
Bei genauerer Betrachtung werden wir nun feststellen, dass wir das Problem eigentlich nur verlagert haben.
Denn nun kann das Signal immer noch auftreten, wenn wir die Signale wieder frei geben.
Das bedeutet, sobald wir die Signale freigeben und uns schlafen legen, ist ein kurzer Zeitraum, in dem ein Signal auftreten kann und dasselbe Problem, das wir vorher hatten, erneut auftritt.
Tatsächlich haben wir die Wahrscheinlichkeit sogar erhöht, dass das Problem nun auftritt, da wir die Signale nun blockieren, noch bevor die Eventvariable ausgewertet wird.
Solange ein Signal blockiert ist, kann es nicht zugestellt werden.
Wenn es jedoch deblockiert wird, kann es sofort zugestellt werden.
Die Konsequenz aus der Sache ist also, wir haben keine Möglichkeit, mit den uns bisher bekannten Mitteln dieses Problem aus der Welt zu schaffen.
Stattdessen müssen wir uns nun an die Instanz wenden, die uns die Signale überhaupt zusendet.
Nämlich muss das Betriebssystem eine Operation anbieten, mit der man gleichzeitig Signale deblockieren kann und sich schlafen legen kann.
Denn nur, wenn dies eine atomare Operation ist, können wir dieses Problem lösen.
Andernfalls besteht immer die Möglichkeit, dass ein Signal genau zu dem Zeitpunkt kommt, an dem man es nicht möchte.
Und das Mittel der Wahl, das uns die POSIX-Schnittstelle nun an die Hand gibt, ist der SIXUSPEND-System-Aufruf.
SIXUSPEND implementiert genau das, was wir brauchen.
Mit SIXUSPEND können wir eine neue Signalmaske setzen und damit Signale deblockieren und uns gleichzeitig schlafen legen.
Zugänglich über
Offener Zugang
Dauer
00:06:42 Min
Aufnahmedatum
2020-12-01
Hochgeladen am
2020-12-01 15:58:25
Sprache
de-DE