C Language
Signalverarbeitung
Suche…
Syntax
- void (* signal (int sig, void (* func) (int))) (int);
Parameter
Parameter | Einzelheiten |
---|---|
sig | Das Signal, das den Signal-Handler auf " SIGABRT , " SIGFPE , " SIGILL , " SIGTERM , " SIGINT , " SIGSEGV oder einen durch die Implementierung definierten Wert setzen soll |
func | Der Signalhandler, einer der folgenden: SIG_DFL für den Standardhandler, SIG_IGN zum Ignorieren des Signals oder ein Funktionszeiger mit der Signatur void foo(int sig); . |
Bemerkungen
Die Verwendung von Signalhandlern mit nur den Garantien des C-Standards unterliegt verschiedenen Einschränkungen, was im benutzerdefinierten Signalhandler möglich oder nicht möglich ist.
Wenn die benutzerdefinierte Funktion während der Behandlung von
SIGSEGV
,SIGFPE
,SIGILL
oder einem anderen implementierungsdefinierten Hardware-Interrupt zurückkehrt, ist das Verhalten durch den C-Standard nicht definiert. Dies liegt daran, dass die Schnittstelle von C keine Mittel zur Änderung des fehlerhaften Zustands gibt (z. B. nach einer Division durch0
) und daher bei der Rückkehr des Programms genau der gleiche fehlerhafte Zustand ist wie vor dem Auftreten des Hardware-Interrupts.Wenn die benutzerdefinierte Funktion als Ergebnis eines
abort
oderraise
aufgerufen wurderaise
darf der Signalhandler nicht erneutraise
aufrufen.Signale können während jeder Operation eintreffen, und daher kann die Unteilbarkeit der Operationen im Allgemeinen nicht garantiert werden, und die Signalverarbeitung funktioniert bei der Optimierung nicht gut. Daher müssen alle Änderungen an den Daten in einem Signalhandler an Variablen vorgenommen werden
- vom Typ
sig_atomic_t
(alle Versionen) oder einemsig_atomic_t
atomaren Typ (seit C11, optional) - das sind
volatile
qualifiziert.
- vom Typ
Bei anderen Funktionen der C-Standardbibliothek werden diese Einschränkungen normalerweise nicht beachtet, da sie möglicherweise Variablen im globalen Status des Programms ändern. Der C-Standard gibt nur Garantien für
abort
,_Exit
(seit C99),quick_exit
(seit C11),signal
(für dieselbe Signalnummer) und einige atomare Operationen (seit C11).
Das Verhalten ist vom C-Standard nicht definiert, wenn eine der oben genannten Regeln verletzt wird. Plattformen können über bestimmte Erweiterungen verfügen, diese sind jedoch im Allgemeinen über diese Plattform nicht portierbar.
Normalerweise haben Systeme eine eigene Liste von Funktionen, die asynchrones Signalsicher sind , d. H. Von C-Bibliotheksfunktionen, die von einem Signalhandler verwendet werden können. ZB ist oft
printf
eine dieser Funktionen.Insbesondere definiert der C-Standard nicht viel über die Interaktion mit seiner Thread-Schnittstelle (seit C11) oder mit plattformspezifischen Thread-Bibliotheken wie POSIX-Threads. Solche Plattformen müssen die Interaktion solcher Thread-Bibliotheken mit eigenen Signalen festlegen.
Signalbehandlung mit "Signal ()"
Signalnummern können synchron sein (wie SIGSEGV
- Segmentierungsfehler), wenn sie durch eine Fehlfunktion des Programms selbst ausgelöst werden, oder asynchron (wie SIGINT
- interaktive Aufmerksamkeit), wenn sie von außerhalb des Programms initiiert werden, z. B. durch Tastendruck als Cntrl-C
.
Die Funktion signal()
ist Teil des ISO-C-Standards und kann verwendet werden, um eine Funktion für die Verarbeitung eines bestimmten Signals zuzuweisen
#include <stdio.h> /* printf() */
#include <stdlib.h> /* abort() */
#include <signal.h> /* signal() */
void handler_nonportable(int sig)
{
/* undefined behavior, maybe fine on specific platform */
printf("Catched: %d\n", sig);
/* abort is safe to call */
abort();
}
sig_atomic_t volatile finished = 0;
void handler(int sig)
{
switch (sig) {
/* hardware interrupts should not return */
case SIGSEGV:
case SIGFPE:
case SIGILL:
/* quick_exit is safe to call */
quick_exit(EXIT_FAILURE);
/* use _Exit in pre-C11 */
_Exit(EXIT_FAILURE);
default:
/* Reset the signal to the default handler,
so we will not be called again if things go
wrong on return. */
signal(sig, SIG_DFL);
/* let everybody know that we are finished */
finished = sig;
return;
}
}
int main(void)
{
/* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
if (signal(SIGSEGV, &handler) == SIG_ERR) {
perror("could not establish handler for SIGSEGV");
return EXIT_FAILURE;
}
/* Catch the SIGTERM signal, termination request */
if (signal(SIGTERM, &handler) == SIG_ERR) {
perror("could not establish handler for SIGTERM");
return EXIT_FAILURE;
}
/* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
signal(SIGINT, SIG_IGN);
/* Do something that takes some time here, and leaves
the time to terminate the program from the keyboard. */
/* Then: */
if (finished) {
fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
return EXIT_FAILURE;
}
/* Try to force a segmentation fault, and raise a SIGSEGV */
{
char* ptr = 0;
*ptr = 0;
}
/* This should never be executed */
return EXIT_SUCCESS;
}
Die Verwendung von signal()
wichtige Einschränkungen, was Sie in den Signalhandlern tun dürfen. Weitere Informationen finden Sie in den Anmerkungen.
POSIX empfiehlt die Verwendung von sigaction()
anstelle von signal()
, da dessen Verhalten nicht genau angegeben ist und die Implementierung stark variiert. POSIX definiert auch viel mehr Signale als den ISO-C-Standard, einschließlich SIGUSR1
und SIGUSR2
, die vom Programmierer für beliebige Zwecke frei verwendet werden können.