Hvordan bruges signalbehandlere på C -sprog?

How Use Signal Handlers C Language



I denne artikel vil vi vise dig, hvordan du bruger signalbehandlere i Linux ved hjælp af C -sprog. Men først vil vi diskutere, hvad der er signal, hvordan det vil generere nogle fælles signaler, som du kan bruge i dit program, og derefter vil vi se, hvordan forskellige signaler kan håndteres af et program, mens programmet udfører. Så lad os starte.

Signal

Et signal er en begivenhed, der genereres for at underrette en proces eller tråd om, at en vigtig situation er ankommet. Når en proces eller tråd har modtaget et signal, stopper processen eller tråden, hvad den gør, og foretager en handling. Signal kan være nyttigt til kommunikation mellem processer.





Standardsignaler

Signalerne er defineret i header -filen signal.h som en makrokonstant. Signalnavn er startet med et SIG og efterfulgt af en kort beskrivelse af signalet. Så hvert signal har en unik numerisk værdi. Dit program bør altid bruge navnet på signalerne, ikke signalernes nummer. Årsagen er, at signalnummeret kan variere alt efter system, men betydningen af ​​navne vil være standard.



Makroen NSIG er det samlede antal definerede signaler. Værdien af NSIG er et større end det samlede antal definerede signaler (Alle signalnumre tildeles i rækkefølge).



Følgende er standardsignalerne:





Signalnavn Beskrivelse
OPSKRIFT Afbryd processen. SIGHUP -signalet bruges til at rapportere afbrydelse af brugerens terminal, muligvis fordi en fjernforbindelse går tabt eller lægger på.
SKILT Afbryd processen. Når brugeren skriver INTR -tegnet (normalt Ctrl + C) sendes SIGINT -signalet.
SIGQUIT Afslut processen. Når brugeren skriver QUIT -tegnet (normalt Ctrl + ), sendes SIGQUIT -signalet.
FORSEGLE Ulovlig instruktion. Når der gøres et forsøg på at udføre skrald eller privilegeret instruktion, genereres SIGILL -signalet. SIGILL kan også genereres, når stakken flyder over, eller når systemet har problemer med at køre en signalhåndterer.
SIGTRAP Sporfælde. En breakpoint -instruktion og anden trap -instruktion vil generere SIGTRAP -signalet. Debuggeren bruger dette signal.
SIGABRT Abort. SIGABRT -signalet genereres, når funktionen abort () kaldes. Dette signal angiver en fejl, der registreres af programmet selv og rapporteres af funktionskaldet ().
SIGFPE Flydende undtagelse. Når der opstod en dødelig aritmetisk fejl, genereres SIGFPE -signalet.
SIGUSR1 og SIGUSR2 Signalerne SIGUSR1 og SIGUSR2 kan bruges som du ønsker. Det er nyttigt at skrive en signalbehandler for dem i programmet, der modtager signalet til simpel kommunikation mellem processer.

Standardhandling af signaler

Hvert signal har en standardhandling, et af følgende:

Semester: Processen afsluttes.
Kerne: Processen vil afslutte og producere en kernedumpfil.
Ign: Processen ignorerer signalet.
Hold op: Processen stopper.
Konto: Processen vil fortsætte med at blive stoppet.



Standardhandling kan ændres ved hjælp af håndteringsfunktion. Nogle signalers standardhandling kan ikke ændres. SIGKILL og SIGABRT signalets standardhandling kan ikke ændres eller ignoreres.

Signalhåndtering

Hvis en proces modtager et signal, har processen et valg af handling for den slags signal. Processen kan ignorere signalet, kan angive en håndteringsfunktion eller acceptere standardhandlingen for den slags signal.

  • Hvis den angivne handling for signalet ignoreres, kasseres signalet med det samme.
  • Programmet kan registrere en handler -funktion ved hjælp af funktion som f.eks signal eller tilslutning . Dette kaldes en handler fanger signalet.
  • Hvis signalet hverken er blevet håndteret eller ignoreret, finder dets standardhandling sted.

Vi kan håndtere signalet ved hjælp af signal eller tilslutning fungere. Her ser vi, hvordan det enkleste signal() funktion bruges til håndtering af signaler.

intsignal() (intskilt, ugyldig (*fungere)(int))

Det signal() vil ringe til fungere funktion, hvis processen modtager et signal skilt . Det signal() returnerer en markør til funktion fungere hvis det lykkes, eller det returnerer en fejl til errno og -1 ellers.

Det fungere markøren kan have tre værdier:

  1. SIG_DFL : Det er en markør til systemets standardfunktion SIG_DFL() , erklærede i h header -fil. Det bruges til at foretage standard handling af signalet.
  2. SIG_IGN : Det er en fingerpeg til system ignorering funktion SIG_IGN () , erklærede i h header -fil.
  3. Brugerdefineret handlerfunktionsmarkør : Den brugerdefinerede handlerfunktionstype er ugyldig (*) (int) , betyder, at returtype er ugyldig og et argument af typen int.

Grundlæggende eksempel på signalhåndtering

#omfatte
#omfatte
#omfatte
ugyldigsig_handler(intskilt){

// Returtype for handlerfunktionen skal være ugyldig
printf (' nInside handler -funktion n');
}

intvigtigste(){
signal(SKILT,sig_handler); // Registrer signalbehandler
til(intjeg=1;;jeg++){ //Uendelig løkke
printf ('%d: Inde i hovedfunktionen n',jeg);
søvn(1); // Forsinkelse i 1 sekund
}
Vend tilbage 0;
}

I skærmbilledet af output fra eksempel1.c kan vi se, at uendelig sløjfe udfører i hovedfunktionen. Når brugeren skrev Ctrl+C, stopper hovedfunktionsudførelsen, og signalets handlerfunktion aktiveres. Efter afslutning af håndteringsfunktionen blev hovedfunktionsudførelsen genoptaget. Når brugeren skrev Ctrl+, afsluttes processen.

Ignorer signaleksempel

#omfatte
#omfatte
#omfatte
intvigtigste(){
signal(SKILT,SIG_IGN); // Registrer signalhåndtereren for at ignorere signalet

til(intjeg=1;;jeg++){ //Uendelig løkke
printf ('%d: Inde i hovedfunktionen n',jeg);
søvn(1); // Forsinkelse i 1 sekund
}
Vend tilbage 0;
}

Her er handler -funktion registreret til SIG_IGN () funktion til ignorering af signalhandlingen. Så når brugeren skrev Ctrl+C, SKILT signal genererer, men handlingen ignoreres.

Omregistrer eksempel på signalhåndterer

#omfatte
#omfatte
#omfatte

ugyldigsig_handler(intskilt){
printf (' nInside handler -funktion n');
signal(SKILT,SIG_DFL); // Registrer signalbehandleren igen for standardhandling
}

intvigtigste(){
signal(SKILT,sig_handler); // Registrer signalbehandler
til(intjeg=1;;jeg++){ //Uendelig løkke
printf ('%d: Inde i hovedfunktionen n',jeg);
søvn(1); // Forsinkelse i 1 sekund
}
Vend tilbage 0;
}

I skærmbilledet af output fra Eksempel3.c kan vi se, at når brugeren første gang skrev Ctrl+C, kaldes handlerfunktionen op. I håndteringsfunktionen registreres signalbehandleren igen til SIG_DFL for standard handling af signalet. Når brugeren skrev Ctrl+C for anden gang, afsluttes processen, hvilket er standardhandlingen for SKILT signal.

Afsendelse af signaler:

En proces kan også eksplicit sende signaler til sig selv eller til en anden proces. raise () og kill () funktion kan bruges til at sende signaler. Begge funktioner erklæres i signal.h header -fil.

int hæve (intskilt)

Hæve () -funktionen, der bruges til at sende signal skilt til kaldprocessen (sig selv). Den returnerer nul, hvis den lykkes, og en værdi uden nul, hvis den fejler.

intdræbe(pid_t pid, intskilt)

Kill -funktionen, der bruges til at sende et signal skilt til en proces eller procesgruppe angivet af pid .

SIGUSR1 Signal Handler Eksempel

#omfatte
#omfatte

ugyldigsig_handler(intskilt){
printf ('Inside handler -funktion n');
}

intvigtigste(){
signal(SIGUSR1,sig_handler); // Registrer signalbehandler
printf ('Indvendig hovedfunktion n');
hæve (SIGUSR1);
printf ('Indvendig hovedfunktion n');
Vend tilbage 0;
}

Her sender processen SIGUSR1 -signal til sig selv ved hjælp af raise () -funktionen.

Hæv med Kill eksempelprogram

#omfatte
#omfatte
#omfatte
ugyldigsig_handler(intskilt){
printf ('Inside handler -funktion n');
}

intvigtigste(){
pid_t pid;
signal(SIGUSR1,sig_handler); // Registrer signalbehandler
printf ('Indvendig hovedfunktion n');
pid=getpid(); // Proces -id af sig selv
dræbe(pid,SIGUSR1); // Send SIGUSR1 til sig selv
printf ('Indvendig hovedfunktion n');
Vend tilbage 0;
}

Her sender processen SIGUSR1 signal til sig selv ved hjælp af dræbe() fungere. getpid () bruges til at få proces -id'et af sig selv.

I det næste eksempel vil vi se, hvordan forælder og barn processer kommunikerer (Inter Process Communication) ved hjælp af dræbe() og signalfunktion.

Forældres barnekommunikation med signaler

#omfatte
#omfatte
#omfatte
#omfatte
ugyldigsig_handler_parent(intskilt){
printf ('Forælder: Modtog et svarsignal fra barn n');
}

ugyldigsig_handler_child(intskilt){
printf ('Barn: Modtog et signal fra forælderen n');
søvn(1);
dræbe(blive ked af det(),SIGUSR1);
}

intvigtigste(){
pid_t pid;
hvis((pid=gaffel())<0){
printf ('Gaffel mislykkedes n');
Afslut (1);
}
/ * Børneproces */
andet hvis(pid==0){
signal(SIGUSR1,sig_handler_child); // Registrer signalbehandler
printf ('Barn: venter på signal n');
pause();
}
/ * Forældreproces */
andet{
signal(SIGUSR1,sig_handler_parent); // Registrer signalbehandler
søvn(1);
printf ('Forælder: sender signal til barn n');
dræbe(pid,SIGUSR1);
printf ('Forælder: venter på svar n');
pause();
}
Vend tilbage 0;
}

Her, gaffel() funktion opretter underordnet proces og returnerer nul til underordnet proces og underordnet proces -id til forælderproces. Så pid er blevet kontrolleret for at bestemme forældrenes og barnets proces. I forældreprocessen sover den i 1 sekund, så barneprocessen kan registrere signalhåndteringsfunktionen og vente på signalet fra forælderen. Send efter 1 sekund forælderproces SIGUSR1 signal til barneproces og vent på responssignal fra barn. I en barneproces venter det først på signal fra forælderen, og når signalet modtages, aktiveres håndteringsfunktionen. Fra behandlerfunktionen sender barneprocessen en anden SIGUSR1 signal til forælderen. Her getppid () funktion bruges til at hente forælderproces -id.

Konklusion

Signal i Linux er et stort emne. I denne artikel har vi set, hvordan man håndterer signal fra det helt grundlæggende, og får også en viden om, hvordan signalet genererer, hvordan en proces kan sende signal til sig selv og anden proces, hvordan signal kan bruges til kommunikation mellem processer.