C Programmeren

Hoe signaalhandlers in C-taal te gebruiken?

Hoe signaalhandlers in C-taal te gebruiken?
In dit artikel laten we je zien hoe je signaalhandlers in Linux gebruikt met behulp van C-taal. Maar eerst zullen we bespreken wat een signaal is, hoe het enkele veelvoorkomende signalen genereert die u in uw programma kunt gebruiken en dan zullen we kijken hoe verschillende signalen door een programma kunnen worden verwerkt terwijl het programma wordt uitgevoerd. Dus laten we beginnen.

Signaal

Een signaal is een gebeurtenis die wordt gegenereerd om een ​​proces of thread op de hoogte te stellen dat er een belangrijke situatie is aangebroken. Wanneer een proces of thread een signaal heeft ontvangen, zal het proces of de thread stoppen met wat het doet en actie ondernemen. Signaal kan nuttig zijn voor communicatie tussen processen.

Standaard signalen

De signalen worden gedefinieerd in het headerbestand signaal.h als een macroconstante. Signaalnaam is begonnen met een "SIG" en gevolgd door een korte beschrijving van het signaal. Elk signaal heeft dus een unieke numerieke waarde. Uw programma moet altijd de naam van de signalen gebruiken, niet het signaalnummer. De reden is dat het signaalnummer per systeem kan verschillen, maar de betekenis van namen is standaard.

de macro NSIG is het totale aantal gedefinieerde signalen. De waarde van NSIG is één groter dan het totale aantal gedefinieerde seinen (alle seinnummers worden opeenvolgend toegewezen).

Hieronder volgen de standaard signalen:

Signaalnaam: Omschrijving
SIGHUP Hang het proces op. Het SIGHUP-signaal wordt gebruikt om te melden dat de terminal van de gebruiker is verbroken, mogelijk omdat een externe verbinding is verbroken of wordt opgehangen.
SIGINT Onderbreek het proces. Wanneer de gebruiker het INTR-teken typt (normaal Ctrl + C), wordt het SIGINT-signaal verzonden.
SIGQUIT Stop het proces. Wanneer de gebruiker het QUIT-teken typt (normaal gesproken Ctrl + \) wordt het SIGQUIT-signaal verzonden.
SIGILL Illegale instructie. Wanneer een poging wordt gedaan om afval of geprivilegieerde instructies uit te voeren, wordt het SIGILL-signaal gegenereerd. SIGILL kan ook worden gegenereerd wanneer de stapel overloopt, of wanneer het systeem problemen heeft met het uitvoeren van een signaalverwerker.
SIGTRAP Trace val. Een breekpuntinstructie en andere trapinstructie zullen het SIGTRAP-signaal genereren. De debugger gebruikt dit signaal.
SIGABRT Afbreken. Het SIGABRT-signaal wordt gegenereerd wanneer de functie abort() wordt aangeroepen. Dit signaal geeft een fout aan die door het programma zelf is gedetecteerd en gerapporteerd door de functie-aanroep abort().
SIGFPE Drijvende-komma uitzondering. Wanneer een fatale rekenfout is opgetreden, wordt het SIGFPE-signaal gegenereerd.
SIGUSR1 en SIGUSR2 De signalen SIGUSR1 en SIGUSR2 kunnen naar wens worden gebruikt. Het is handig om een ​​signaalbehandelaar voor hen te schrijven in het programma dat het signaal ontvangt voor eenvoudige communicatie tussen processen.

Standaardactie van signalen

Elk signaal heeft een standaardactie, een van de volgende:

Termijn: Het proces wordt beëindigd.
Kern: Het proces wordt beëindigd en produceert een kerndumpbestand.
Ign: Het proces negeert het signaal.
Hou op: Het proces stopt.
vervolg: Het proces wordt voortgezet nadat het is gestopt.

Standaardactie kan worden gewijzigd met behulp van de handlerfunctie. De standaardactie van sommige signalen kan niet worden gewijzigd. SIGKILL en SIGABRT de standaardactie van het signaal kan niet worden gewijzigd of genegeerd.

Signaalverwerking

Als een proces een signaal ontvangt, heeft het proces een actiekeuze voor dat soort signaal. Het proces kan het signaal negeren, een handlerfunctie specificeren of de standaardactie voor dat soort signaal accepteren.

We kunnen het signaal verwerken met behulp van: signaal of sigactie functie. Hier zien we hoe de eenvoudigste signaal() functie wordt gebruikt voor het verwerken van signalen.

int signaal () (int signum, void (*func)(int))

De signaal() zal de bellen func functie als het proces een signaal ontvangt signum. De signaal() geeft een aanwijzer terug naar functie func indien succesvol of het retourneert een fout naar errno en anders -1.

De func aanwijzer kan drie waarden hebben:

  1. SIG_DFL: Het is een verwijzing naar de standaardfunctie van het systeem SIG_DFL(), verklaard in h header-bestand. Het wordt gebruikt voor het nemen van standaardactie van het signaal.
  2. SIG_IGN: Het is een verwijzing naar de functie voor het negeren van het systeem SIG_IGN(),verklaard in h header-bestand.
  3. Door de gebruiker gedefinieerde handlerfunctie-aanwijzer: Het door de gebruiker gedefinieerde handlerfunctietype is nietig(*)(int), betekent dat het retourtype ongeldig is en één argument van het type int.

Voorbeeld van basissignaalverwerker

#include
#include
#include
void sig_handler(int signum)
//Retourtype van de handlerfunctie moet ongeldig zijn
printf("\nBinnen handler functie\n");

int hoofd()
signaal (SIGINT, sig_handler); // Signaalbehandelaar registreren
for(int i=1;;i++)    //Oneindige lus
printf("%d : Binnen hoofdfunctie\n",i);
slaap(1); // Vertraging voor 1 seconde

retourneer 0;

In de schermafbeelding van de uitvoer van Voorbeeld1.c, we kunnen zien dat in de hoofdfunctie oneindige lus wordt uitgevoerd. Wanneer de gebruiker Ctrl+C typt, stopt de uitvoering van de hoofdfunctie en wordt de handlerfunctie van het signaal aangeroepen. Na voltooiing van de handlerfunctie, wordt de uitvoering van de hoofdfunctie hervat. Als de gebruiker Ctrl+\ typt, wordt het proces afgesloten.

Negeer signalen Voorbeeld

#include
#include
#include
int hoofd()
signaal (SIGINT,SIG_IGN); // Registreer signaalbehandelaar voor het negeren van het signaal
for(int i=1;;i++)    //Oneindige lus
printf("%d : Binnen hoofdfunctie\n",i);
slaap(1); // Vertraging voor 1 seconde

retourneer 0;

Hier is de handlerfunctie registreren bij SIG_IGN() functie voor het negeren van de signaalactie. Dus toen de gebruiker Ctrl+C . typte,  SIGINT signaal wordt gegenereerd, maar de actie wordt genegeerd.

Voorbeeld van signaalhandler opnieuw registreren

#include
#include
#include
void sig_handler(int signum)
printf("\nBinnen handler functie\n");
signaal (SIGINT,SIG_DFL); // Re Registreer signaalhandler voor standaardactie

int hoofd()
signaal (SIGINT, sig_handler); // Signaalbehandelaar registreren
for(int i=1;;i++)    //Oneindige lus
printf("%d : Binnen hoofdfunctie\n",i);
slaap(1); // Vertraging voor 1 seconde

retourneer 0;

In de schermafbeelding van de uitvoer van Voorbeeld3.c, we kunnen zien dat wanneer de gebruiker voor het eerst Ctrl+C typte, de handlerfunctie werd aangeroepen. In de handlerfunctie registreert de signaalhandler zich opnieuw bij: SIG_DFL voor standaardactie van het signaal:. Wanneer de gebruiker voor de tweede keer Ctrl+C typt, wordt het proces beëindigd, wat de standaardactie is van SIGINT signaal.

Signalen verzenden:

Een proces kan ook expliciet signalen naar zichzelf of naar een ander proces sturen. de functie raise() en kill() kunnen worden gebruikt voor het verzenden van signalen. Beide functies worden gedeclareerd in signaal.h header-bestand.

int verhogen (int signum)

De functie raise() die wordt gebruikt voor het verzenden van signalen signum naar het belproces (zelf). Het geeft nul terug als het lukt en een waarde die niet nul is als het mislukt.

int kill(pid_t pid, int signum)

De kill-functie die wordt gebruikt voor het verzenden van een signaal signum naar een proces of procesgroep gespecificeerd door pid.

SIGUSR1 Signaal Handler Voorbeeld

#include
#include
void sig_handler(int signum)
printf("Binnen handler functie\n");

int hoofd()
signaal (SIGUSR1, sig_handler); // Signaalbehandelaar registreren
printf("Binnen hoofdfunctie\n");
verhogen (SIGUSR1);
printf("Binnen hoofdfunctie\n");
retourneer 0;

Hier stuurt het proces het SIGUSR1-signaal naar zichzelf met behulp van de functie raise().

Raise with Kill Voorbeeldprogramma

#include
#include
#include
void sig_handler(int signum)
printf("Binnen handler functie\n");

int hoofd()
pid_t pid;
signaal (SIGUSR1, sig_handler); // Signaalbehandelaar registreren
printf("Binnen hoofdfunctie\n");
pid=getpid(); //Proces-ID van zichzelf
kill(pid,SIGUSR1); // Stuur SIGUSR1 naar zichzelf
printf("Binnen hoofdfunctie\n");
retourneer 0;

Hier, het proces verzenden: SIGUSR1 signaal naar zichzelf met behulp van doden() functie. getpid() wordt gebruikt om de proces-ID van zichzelf te krijgen.

In het volgende voorbeeld zullen we zien hoe ouder- en kindprocessen communiceren (Interprocescommunicatie) met behulp van doden() en signaalfunctie:.

Ouder-kindcommunicatie met signalen

#include
#include
#include
#include
void sig_handler_parent(int signum)
printf("Ouder: Antwoordsignaal ontvangen van kind \n");

void sig_handler_child(int signum)
printf("Kind: signaal ontvangen van ouder \n");
slaap(1);
kill(getppid(),SIGUSR1);

int hoofd()
pid_t pid;
if((pid=vork())<0)
printf("Fork mislukt\n");
uitgang(1);

/* Onderliggend proces */
anders if(pid==0)
signaal (SIGUSR1, sig_handler_child); // Signaalbehandelaar registreren
printf("Kind: wacht op signaal\n");
pauze();

/* Ouderproces */
anders
signaal (SIGUSR1, sig_handler_parent); // Signaalbehandelaar registreren
slaap(1);
printf("Ouder: signaal naar kind\n");
kill(pid,SIGUSR1);
printf("Ouder: wacht op antwoord\n");
pauze();

retourneer 0;

Hier, vork() functie maakt een onderliggend proces en retourneert nul naar het onderliggende proces en de ID van het onderliggende proces naar het bovenliggende proces. Dus pid is gecontroleerd om het ouder- en kindproces te bepalen. In het ouderproces wordt het gedurende 1 seconde geslapen, zodat het kindproces de signaalverwerkingsfunctie kan registreren en op het signaal van de ouder kan wachten. Na 1 seconde ouderproces verzenden SIGUSR1 signaal naar kind verwerken en wachten op het antwoordsignaal van kind. In het kindproces wacht het eerst op het signaal van de ouder en wanneer het signaal wordt ontvangen, wordt de handlerfunctie aangeroepen. Vanuit de handlerfunctie stuurt het onderliggende proces een ander SIGUSR1 signaal naar ouder. Hier getppid() functie wordt gebruikt voor het verkrijgen van de ouderproces-ID.

Conclusie

Signaal in Linux is een groot onderwerp. In dit artikel hebben we gezien hoe signaal vanaf de basis moet worden verwerkt, en we hebben ook kennis gekregen van hoe het signaal wordt gegenereerd, hoe een proces een signaal naar zichzelf en andere processen kan sturen, hoe een signaal kan worden gebruikt voor communicatie tussen processen.

OSD-overlay tonen in Linux-apps en -games op volledig scherm
Het spelen van games op volledig scherm of het gebruik van apps in de modus volledig scherm zonder afleiding kan u afsnijden van relevante systeeminfo...
Top 5 Game Capture-kaarten
We hebben allemaal gezien en genoten van streaming gameplays op YouTube. PewDiePie, Jakesepticye en Markiplier zijn slechts enkele van de beste gamers...
Hoe een spel op Linux te ontwikkelen
Tien jaar geleden zouden niet veel Linux-gebruikers voorspellen dat hun favoriete besturingssysteem ooit een populair spelplatform voor commerciële vi...