Definition | #include <signal.h> void (*signal(int sig, void (*fkt) (int))) (int); Die Funktion Man muss zwei Arten von Signalen unterscheiden, die ein Programm erhalten und behandeln kann. Sie unterscheiden sich in der Art der Auslösung. In der Folge davon wird ihre Behandlung intern unterschiedlich realisiert:
Hat ein Programm keine Behandlung von Signalen vorgesehen, wird bei Eintritt eines Signals das Programm abgebrochen. Das Programm kann ein Signal aber auch abfangen. Dazu muss man die Funktion
Im Folgenden werden diese drei Möglichkeiten der Signalbehandlung etwas ausführlicher erläutert, um dabei vor allem auf die unterschiedliche Behandlung von STXIT-Ereignissen und ProgrammabbruchProgrammabbruch erfolgt dann, wenn das Programm keine Signalbehandlung vorsieht oder wenn STXIT-Ereignis: Es erfolgt die Standard-Abbruchreaktion durch das Betriebssystem. Das Programm wird abgebrochen, und es werden Informationen ausgegeben zur Abbruchadresse und zum Fehlergewicht sowie eine DUMP-Meldung:
Es erfolgt eine C-spezifische Programmbeendigung durch exit(-1) und es werden folgende Meldungen ausgegeben:
Signal ignorierenEin Signal wird ignoriert, wenn Signal gemäß eigener Funktion fkt behandelnEin Signal wird gemäß einer selbst geschriebenen Funktion fkt behandelt, wenn STXIT-Ereignis: fkt wird intern als eigener STXIT-Contingency-Prozess realisiert, das übrige Programm als sog. „Basisprozess“. Die Steuerung wird durch das Betriebssystem vorgenommen.
fkt wird intern als „normale“ C-Funktion behandelt und nicht über den Contingency-Mechanismus realisiert. Die Steuerung obliegt dem C-Laufzeitsystem. Weitere Einzelheiten bzgl. der unterschiedlichen Realisierung und der damit verbundenen unterschiedlichen Möglichkeiten von | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameter | int sig Signal, das behandelt werden soll. Für sig können symbolische Konstanten eingesetzt werden, die in der folgenden Tabelle unter „SIGNR“ aufgelistet sind. Diese Konstanten sind in der Include-Datei <signal.h> definiert.
Die symbolische Konstante für die Signalnummer kann durch einen weiteren symbolischen Namen ergänzt werden, z.B. Ohne Zusatz ist SIG_TSK voreingestellt.
void (*fkt)(int) Name der Funktion, die bei Eintritt eines Signals aufgerufen werden soll. Diese Funktion erhält als einziges Argument die Signalnummer vom Typ In <signal.h> gibt es zwei vordefinierte Funktionen:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Returnwert | Vor dem | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bei Erfolg. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SIG_ERR (= 1) | bei Fehler, z.B. wenn sig keine gültige Signalnummer ist oder fkt auf eine unzulässige Adresse zeigt. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Hinweise | Das Signal SIGKILL kann nicht abgefangen werden, d.h. ihm kann weder eine selbst geschriebene Funktion noch SIG_IGN zugeordnet werden. Wenn für ein Signal, dem bereits eine Signalbehandlung zugeordnet ist, eine zweite Funktion zur Signalbehandlung angemeldet wird, wird zunächst die erste Funktion abgemeldet, bevor die neue Funktion angemeldet wird. Aus diesem Grunde ist für eine kurze Zeitspanne keine Signalbehandlung für das betroffene Signal angemeldet. Aus einer Funktion, die dem Signal SIGTERM zugeordnet ist, kann nicht mit einem Bei Programmstart ist für alle Signale SIG_DFL voreingestellt (vgl. nächsten Absatz). Temporäre/permanente Zuordnung: In vielen Implementierungen (z.B. UNIX) und auch im ANSI-Standard ist die temporäre Zuordnung eines Signals zu einer Funktion vorgesehen. Das bedeutet: Die vom Anwender vorgenommene Zuordnung einer Funktion zu einer Signalnummer gilt nur temporär für ein einziges Auftreten dieses Signals. Die Zuordnung wird nach Auftritt des Signals aufgehoben und auf SIG_DFL (Programmabbruch) zurückgesetzt. Lediglich die Zuordnung SIG_IGN (Signal ignorieren) gilt permanent für mehrmaliges Auftreten des entsprechenden Signals.
Probleme können sich bei den drei verschiedenen Signalnummern ergeben, die durch dieselbe STXIT-Ereignisklasse (PROCHK) abgebildet werden. Folgende signal(SIGILL, fkt1); signal(SIGFPE, fkt2); signal(SIGDVZ, fkt3); STXIT-Ereignis: Es wird in jedem Fall fkt3 aufgerufen, wenn die Signale SIGILL und SIGFPE über den STXIT-Contingency-Mechanismus abgefangen werden. Aber selbst, wenn nur für ein Signal ein
Werden die Signale jedoch mit der Eine Funktion, die einem Signal zugeordnet ist, benötigt für ihren Ablauf eine intakte C-Umgebung. Daher werden bei regulärer Programmbeendigung unmittelbar vor dem Abbau der C-Umgebung alle Signalroutinen abgemeldet. Danach eintretende Ereignisse werden nicht mehr abgefangen, auch nicht SIGTERM. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Beispiel | Folgendes Programm fängt mit der Funktion fkt die STXIT-Ereignisse SIGDVZ (Division durch 0) und SIGINT (Unterbrechung mit der K2-Taste) ab und gibt eine entsprechende Fehlermeldung aus. Mittels der Funktionen #include <stdio.h> #include <signal.h> #include <setjmp.h> jmp_buf env; void fkt(int sig) { if(sig == SIGDVZ + SIG_PS) printf("Divisionsfehler, Eingabe wiederholen\n"); if(sig == SIGINT + SIG_PS) printf("K2-Taste gedrueckt, Eingabe wiederholen\n"); longjmp(env, 1); } int main(void) { float a; float b; double z; signal(SIGDVZ + SIG_PS, fkt); signal(SIGINT + SIG_PS, fkt); setjmp(env); printf("Bitte a und b eingeben\n"); /* Unterbrechung mit K2 möglich */ scanf("%f %f", &a, &b); z = a / b; /* Division durch 0 möglich, */ /* falls b = 0 */ printf("z = %f\n", z); printf ("Programmende\n"); return 0; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Siehe auch | alarm, longjmp, raise, setjmp |