Ein Prozess kann von außen mittels kill-Befehl Signale empfangen. Normalerweise >>stirbt<< der Prozess, wenn er ein solches Signal bekommt. Man kann Programme auch so schreiben, dass sie durch einen Signalbehandler auf die Signale reagieren.
signal() installiert Signalhandler
Der Funktion signal() meldet dem Betriebssystem, dass eine Funktion des Programmes bestimmte Signale bearbeiten will.#include <signal.h> signal(int SignalNr, void (*Signalfunktion)(int)); |
SIGTERM: Geregelter Abgang
Das eine Signal, auf das ein Programm immer reagieren sollte ist SIGTERM. Er wird z. B. beim Herunterfahren des Systems an jeden Prozess gesandt. Die typische Reaktion sollte es sein, die Aktivitäten schnellstmöglich einzustellen und einen konsistenten Zustand der Daten zu gewährleisten. Dafür hat es im Falle des Herunterfahrens höchstens 5 Sekunden Zeit. Dann wird es durch einen SIGKILL endgültig erlegt.SIGHUP: Neue Konfiguration einlesen
Besonders bei Hintergrundprozessen ist es inzwischen üblich, das SIGHUP-Signal zu verwenden, um den Prozess dazu zu bewegen, Konfigurationsdateien neu zu lesen. So ist es möglich, Einstellungen zu ändern, ohne den Betrieb zu unterbrechen.Die folgende Tabelle benennt alle Signalkonstanten, die der erste Parameter annehmen kann.
Name | Bedeutung |
---|---|
SIGHUP | (1) Hangup: Terminalabschaltung oder Konfiguration neu einlesen |
SIGINT | Unterbrechung durch ctrl-C oder Delete |
SIGQUIT | Unterbrechung durch ctrl- |
SIGILL | Illegale Anweisung |
SIGTRACE | Im Debugmodus |
SIGIOT | I/O Trap |
SIGKILL | (9) nicht abfangbarer Tötungsaufruf |
SIGBUS | Busfehler |
SIGSEGV | Segmentation Violation |
SIGPIPE | Schreiben auf ein nicht zum Lesen geöffnete Pipe |
SIGALRM | Aufgesetzter Alarm |
SIGTERM | (15) Terminierung |
SIGUSR1 | (16) Benuterdefiniertes Signal zur freien Verfügung |
SIGUSR2 | (17) Benuterdefiniertes Signal zur freien Verfügung |
SIGCLD | Tod eines Sohnprozesses |
SIGPWR | (19) Spannungsproblem |
Beispiel mit SIGHUP
Das folgende Programm fängt einen SIGHUP und gibt bei jedem kill eine Meldung auf dem Bildschirm aus.#include <signal.h> void SigHandler(int Nr) { puts("Signal gefangen"); } main() { signal(SIGHUP, SigHandler); for (;;) ; } |
Signale senden: kill
Auch aus einem Programm heraus können Signale mit der Funktion kill() versendet werden.#include <sys/types.h> #include <signal.h> int kill(int pid, int signal); |
Parameter
Der Parameter pid gibt die Prozessnummer des Empfängers an. Der Parameter signal bezeichnet das zu sendende Signal. Im Erfolgsfall gibt die Funktion 0, ansonsten -1 zurück.Auf Signale warten: pause
Die Funktion blockiert den Prozess und wartet auf ein beliebiges Signal.#include <unistd.h> int pause(void); |
Dieser Aufruf liefert immer -1 als Rückgabewert.
Timeout setzen: alarm
Mit der Funktion alarm() wird ein Alarm aufgesetzt. Sobald die als Parameter übergebenen Sekunden vergangen sind, wird dem Prozess ein Signal SIGALRM zugesandt.Unterbricht ewiges Warten
Diese Funktionalität ist wichtig, wenn man mit blockierenden Einheiten arbeitet, bei denen die Anforderung nach einer gewissen Zeit abgebrochen werden soll. Dies kommt beispielsweise in der Netzwerkprogrammierung vor. Das eintreffende Signal unterbricht die blockierende I/O-Funktionen.#include <unistd.h> long alarm(long Sekunden); |
Wiederholter Alarm
Der Rückgabewert ist 0. Steht allerdings noch ein Signal von einem vorher aufgesetzten Alarm aus, wird dieser Alarm gelöscht und die Anzahl der Sekunden zurückgegeben, die noch bis zum Alarm verblieben wären.Zombies vereiteln
Ein Zombie ist ein verwaister Prozesstabelleneintrag
Ein Zombie ist ein Prozess, der in Wirklichkeit nicht mehr existiert. Genauer gesagt handelt es sich um einen Eintrag in der Prozesstabelle, hinter dem kein echter Prozess mehr steckt. Normalerweise wartet der Vaterprozess auf das Ende des Sohnprozesses. Erst dann läuft er weiter. Dies wird über den Systemaufruf wait() realisiert. Durch diesen Aufruf wird der Vaterprozess in die Warteschlange gesetzt. Der Vater kommt wieder frei, wenn der Sohn beendet wurde und wait() liefert auch den Exitstatus des Sohnes. Diesen hinterlegt der Sohn beim Verscheiden in die Prozesstabelle. Wenn aber der Vater gar keinen wait() ausführt, wird der Eintrag in der Prozesstabelle nie gelöscht. Dieser Eintrag ist der Zombie.Kindersignale ignorieren
Nun gibt es oft Situationen, in denen eben nicht gewartet wird, bis der Sohn verscheidet, sondern eben gerade die Parallelität von Prozessen genutzt werden soll. Das heißt, dass gerade bei Dämonen und Serverprozessen immer die Gefahr besteht, dass Zombies entstehen. Um dies zu vermeiden, kann man das Signal SIG_CLD ignorieren. Das passiert, wenn der Funktion signal() statt der Behandlungsfunktion die Konstante SIG_IGN angegeben word. Dies sagt dem Betriebssystem, dass dieses Signal in Zukunft nicht beachtet werden soll.signal(SIGCLD, SIG_IGN); |
Damit teilt der Vaterprozess mit, dass er keineswegs am weiteren Dasein seines Sohnes interessiert ist und dass bitte Nachrichten nicht für ihn aufgehoben werden sollen.
Diese Seite basiert auf Inhalten aus dem Buch Arnold Willemer: Wie werde ich UNIX-Guru? |