C Language
Signalhantering
Sök…
Syntax
- void (* signal (int sig, void (* func) (int))) (int);
parametrar
Parameter | detaljer |
---|---|
sig | Signalen för att ställa in signalhanteraren till, en av SIGABRT , SIGFPE , SIGILL , SIGTERM , SIGINT , SIGSEGV eller något implementeringsdefinierat värde |
func | Signalhanteraren, som är något av följande: SIG_DFL , för standardhanteraren, SIG_IGN att ignorera signalen, eller en funktionspekare med signaturen void foo(int sig); . |
Anmärkningar
Användningen av signalhanterare med bara garantier från C-standarden sätter olika begränsningar vad som kan eller inte kan göras i den användardefinierade signalhanteraren.
Om den användardefinierade funktionen återgår under hantering av
SIGSEGV
,SIGFPE
,SIGILL
eller någon annan implementeringsdefinerad hårdvaruavbrott, definieras beteendet av C-standarden. Detta beror på att C: s gränssnitt inte ger möjlighet att ändra det felaktiga tillståndet (t.ex. efter en uppdelning med0
) och därmed när programmet returneras är i exakt samma felaktiga tillstånd än innan hårdvaruavbrottet inträffade.Om den användardefinierade funktionen anropades som ett resultat av ett samtal att
abort
ellerraise
, får signalhanteraren inte anroparaise
igen.Signaler kan anlända i mitten av alla operationer, och därför kan man ofta inte garantera operationens odelbarhet och inte heller fungerar signalhantering med optimering. Därför måste alla ändringar av data i en signalhanterare vara till variabler
- av typen
sig_atomic_t
(alla versioner) eller ensig_atomic_t
(sedan C11, valfritt) - som är
volatile
kvalificerade.
- av typen
Andra funktioner från C-standardbiblioteket respekterar vanligtvis inte dessa begränsningar, eftersom de kan ändra variabler i programmets globala tillstånd. C-standarden ger bara garantier för
abort
,_Exit
(sedan C99),quick_exit
(sedan C11),signal
(för samma signalnummer) och vissa atomoperationer (sedan C11).
Beteende definieras inte av C-standarden om någon av ovanstående regler bryts. Plattformar kan ha specifika tillägg, men dessa är i allmänhet inte bärbara bortom plattformen.
Vanligtvis har system sin egen lista över funktioner som är asynkrona signalsäkra , det vill säga C-biblioteksfunktioner som kan användas från en signalhanterare.
printf
ärprintf
bland dessa funktioner.Speciellt definierar C-standarden inte så mycket om interaktionen med dess trådgränssnitt (sedan C11) eller någon plattformsspecifika trådbibliotek som POSIX-trådar. Sådana plattformar måste specificera interaktion mellan sådana trådbibliotek med signaler av sig själva.
Signalhantering med "signal ()"
Signalnummer kan vara synkrona (som SIGSEGV
- segmenteringsfel) när de utlöses av en felaktig funktion i själva programmet eller asynkron (som SIGINT
- interaktiv uppmärksamhet) när de startas utanför programmet, t.ex. av en knapptryckning som Cntrl-C
.
Funktionen signal()
är en del av ISO C-standarden och kan användas för att tilldela en funktion för att hantera en specifik signal
#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;
}
Att använda signal()
sätter viktiga begränsningar vad du får göra i signalhanterarna, se kommentarerna för ytterligare information.
POSIX rekommenderar användning av sigaction()
istället för signal()
grund av dess ospecificerade beteenden och betydande implementeringsvariationer. POSIX definierar också många fler signaler än ISO C-standarden, inklusive SIGUSR1
och SIGUSR2
, som fritt kan användas av programmeraren för alla ändamål.