C Programmering

Hur man använder signalhanterare på C-språk?

Hur man använder signalhanterare på C-språk?
I den här artikeln ska vi visa dig hur du använder signalhanterare i Linux med C-språk. Men först kommer vi att diskutera vad som är signal, hur det kommer att generera några vanliga signaler som du kan använda i ditt program och sedan kommer vi att se hur olika signaler kan hanteras av ett program medan programmet körs. Så, låt oss börja.

Signal

En signal är en händelse som genereras för att meddela en process eller tråd att någon viktig situation har kommit. När en process eller tråd har fått en signal kommer processen eller tråden att stoppa vad den gör och vidta några åtgärder. Signal kan vara användbar för kommunikation mellan processer.

Standard signaler

Signalerna definieras i rubrikfilen signal.h som en makrokonstant. Signalnamnet har börjat med ett “SIG” och följt av en kort beskrivning av signalen. Så, varje signal har ett unikt numeriskt värde. Ditt program ska alltid använda namnet på signalerna, inte signalnumren. Anledningen är att signalnumret kan variera beroende på system men betydelsen av namnen kommer att vara standard.

Makroen NSIG är det totala antalet definierade signaler. Värdet av NSIG är en större än det totala antalet definierade signaler (Alla signalnummer tilldelas i följd).

Följande är standardsignalerna:

Signalnamn Beskrivning
SIGHUP Lägg på processen. SIGHUP-signalen används för att rapportera frånkoppling av användarens terminal, möjligen på grund av att en fjärranslutning försvinner eller läggs på.
SIGINT Avbryt processen. När användaren skriver INTR-tecknet (normalt Ctrl + C) skickas SIGINT-signalen.
SIGQUIT Avsluta processen. När användaren skriver QUIT-tecknet (normalt Ctrl + \) skickas SIGQUIT-signalen.
SIGILL Olaglig instruktion. När man försöker utföra skräp eller privilegierad instruktion genereras SIGILL-signalen. SIGILL kan också genereras när stacken flyter över eller när systemet har problem med att köra en signalhanterare.
SIGTRAP Spårfälla. En brytpunktsinstruktion och annan fällinstruktion genererar SIGTRAP-signalen. Felsökaren använder denna signal.
SIGABRT Avbryta. SIGABRT-signalen genereras när funktionen avbryta () anropas. Denna signal indikerar ett fel som detekteras av själva programmet och rapporteras av funktionen avbryta ().
SIGFPE Flytpunktsundantag. När ett allvarligt aritmetiskt fel inträffade genereras SIGFPE-signalen.
SIGUSR1 och SIGUSR2 Signalerna SIGUSR1 och SIGUSR2 kan användas som du vill. Det är användbart att skriva en signalhanterare för dem i programmet som tar emot signalen för enkel inter-processkommunikation.

Standardåtgärd för signaler

Varje signal har en standardåtgärd, en av följande:

Termin: Processen avslutas.
Kärna: Processen avslutas och producerar en kärndumpfil.
Ign: Processen ignorerar signalen.
Sluta: Processen kommer att stoppa.
Fortsättning: Processen fortsätter att stoppas.

Standardåtgärden kan ändras med hjälp av hanterarfunktionen. Vissa signalers standardåtgärd kan inte ändras. SIGKILL och SIGABRT signalens standardåtgärd kan inte ändras eller ignoreras.

Signalhantering

Om en process tar emot en signal har processen ett val av åtgärder för den typen av signal. Processen kan ignorera signalen, kan ange en hanterarfunktion eller acceptera standardåtgärden för den typen av signal.

Vi kan hantera signalen med signal eller sigaction fungera. Här ser vi hur det enklaste signal() funktionen används för hantering av signaler.

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

De signal() kommer att ringa funk funktion om processen tar emot en signal signum. De signal() returnerar en pekare för att fungera funk om det lyckas eller om det returnerar ett fel till errno och -1 annars.

De funk pekaren kan ha tre värden:

  1. SIG_DFL: Det är en pekare till systemets standardfunktion SIG_DFL (), förklarade i h rubrikfil. Den används för att vidta standardåtgärder för signalen.
  2. SIG_IGN: Det är en pekare till system ignorera funktion SIG_IGN (),förklarade i h rubrikfil.
  3. Användardefinierad pekare för hanterarfunktion: Den användardefinierade hanterarfunktionstypen är ogiltig (*) (int), betyder returtyp är ogiltig och ett argument av typen int.

Exempel på grundläggande signalhanterare

#omfatta
#omfatta
#omfatta
ogiltig sig_handler (int signum)
// Returtypen för hanterarfunktionen ska vara ogiltig
printf ("\ nInnehanteringsfunktion \ n");

int main ()
signal (SIGINT, sig_handler); // Registrera signalhanteraren
för (int i = 1 ;; i ++) // Oändlig slinga
printf ("% d: Inne i huvudfunktionen \ n", i);
sömn (1); // Fördröj i 1 sekund

returnera 0;

I skärmdumpen av utdata från exempel 1.c, vi kan se att i huvudfunktionen utförs oändlig slinga. När användaren skrev Ctrl + C, startar huvudfunktionens körning och signalens hanterarfunktion. Efter slutförandet av hanterarfunktionen återupptogs utförandet av huvudfunktionen. När användartypen skrev Ctrl + \ avslutas processen.

Ignorera exempel på signaler

#omfatta
#omfatta
#omfatta
int main ()
signal (SIGINT, SIG_IGN); // Registrera signalhanteraren för att ignorera signalen
för (int i = 1 ;; i ++) // Oändlig slinga
printf ("% d: Inne i huvudfunktionen \ n", i);
sömn (1); // Fördröj i 1 sekund

returnera 0;

Här registreras hanterarfunktionen till SIG_IGN () funktion för att ignorera signalåtgärden. Så när användaren skrev Ctrl + C,  SIGINT signalen genereras men åtgärden ignoreras.

Omregistrera Signalhanterarexempel

#omfatta
#omfatta
#omfatta
ogiltig sig_handler (int signum)
printf ("\ nInnehanteringsfunktion \ n");
signal (SIGINT, SIG_DFL); // Registrera om signalhanteraren för standardåtgärd

int main ()
signal (SIGINT, sig_handler); // Registrera signalhanteraren
för (int i = 1 ;; i ++) // Oändlig slinga
printf ("% d: Inne i huvudfunktionen \ n", i);
sömn (1); // Fördröj i 1 sekund

returnera 0;

I skärmdumpen av utdata från exempel 3.c, vi kan se att när användaren först skrev Ctrl + C, åkallade hanterarfunktionen. I hanterarfunktionen registreras signalhanteraren om till SIG_DFL för standardåtgärd för signalen. När användaren skrev Ctrl + C för andra gången avslutas processen vilket är standardåtgärden för SIGINT signal.

Skicka signaler:

En process kan också uttryckligen skicka signaler till sig själv eller till en annan process. höja () och döda () funktionen kan användas för att skicka signaler. Båda funktionerna deklareras i signal.h rubrikfil.

int höja (int signum)

Höjningsfunktionen () som används för att skicka signal signum till samtalsprocessen (sig själv). Det returnerar noll om det lyckas och ett icke-nollvärde om det misslyckas.

int kill (pid_t pid, int signum)

Dödfunktionen som används för att skicka en signal signum till en process eller processgrupp som anges av pid.

SIGUSR1 Signalhanterarexempel

#omfatta
#omfatta
ogiltig sig_handler (int signum)
printf ("Inside handler function \ n");

int main ()
signal (SIGUSR1, sig_handler); // Registrera signalhanteraren
printf ("Inne i huvudfunktionen \ n");
höja (SIGUSR1);
printf ("Inne i huvudfunktionen \ n");
returnera 0;

Här skickar processen SIGUSR1-signalen till sig själv med hjälp av höjningsfunktionen ().

Höj med Kill Exempelprogram

#omfatta
#omfatta
#omfatta
ogiltig sig_handler (int signum)
printf ("Inside handler function \ n");

int main ()
pid_t pid;
signal (SIGUSR1, sig_handler); // Registrera signalhanteraren
printf ("Inne i huvudfunktionen \ n");
pid = getpid (); // Process-ID för sig själv
döda (pid, SIGUSR1); // Skicka SIGUSR1 till sig själv
printf ("Inne i huvudfunktionen \ n");
returnera 0;

Här skickar processen SIGUSR1 signal till sig själv med döda() fungera. getpid () används för att få process-ID för sig själv.

I nästa exempel ser vi hur föräldra- och barnprocesser kommunicerar (Inter Process Communication) med hjälp av döda() och signalfunktion.

Föräldrabarns kommunikation med signaler

#omfatta
#omfatta
#omfatta
#omfatta
ogiltigt sig_handler_parent (int signum)
printf ("Förälder: Fick en svarsignal från barnet \ n");

ogiltigt sig_handler_child (int signum)
printf ("Child: fick en signal från föräldern \ n");
sömn (1);
kill (getppid (), SIGUSR1);

int main ()
pid_t pid;
om ((pid = gaffel ())<0)
printf ("Gaffeln misslyckades \ n");
utgång (1);

/ * Barnprocess * /
annars om (pid == 0)
signal (SIGUSR1, sig_handler_child); // Registrera signalhanteraren
printf ("Barn: väntar på signal \ n");
paus();

/ * Föräldraprocess * /
annan
signal (SIGUSR1, sig_handler_parent); // Registrera signalhanteraren
sömn (1);
printf ("Förälder: skickar signal till Child \ n");
döda (pid, SIGUSR1);
printf ("Förälder: väntar på svar \ n");
paus();

returnera 0;

Här, gaffel() funktionen skapar underordnad process och returnerar noll till underordnad process och underordnad process-ID till föräldraprocessen. Så pid har kontrollerats för att avgöra föräldra- och barnprocessen. I föräldraprocessen sov den i 1 sekund så att barnprocessen kan registrera signalhanteringsfunktionen och vänta på signalen från föräldern. Efter 1 sekund överordnad process skicka SIGUSR1 signal till barnprocess och vänta på svarssignalen från barnet. I barnprocessen väntar den först på signal från föräldern och när signalen tas emot anropas hanterarfunktionen. Från hanterarfunktionen skickar barnprocessen en annan SIGUSR1 signal till förälder. Här getppid () funktionen används för att få föräldra-process-ID.

Slutsats

Signal i Linux är ett stort ämne. I den här artikeln har vi sett hur man hanterar signal från det helt grundläggande, och får också kunskap om hur signalen genereras, hur en process kan skicka signal till sig själv och annan process, hur signal kan användas för kommunikation mellan processer.

HD Remastered Games för Linux som aldrig tidigare hade en Linux-version
Många spelutvecklare och utgivare kommer med HD-remaster av gamla spel för att förlänga livstiden för franchisen, snälla fans som begär kompatibilitet...
Hur man använder AutoKey för att automatisera Linux-spel
AutoKey är ett verktyg för desktopautomatisering för Linux och X11, programmerat i Python 3, GTK och Qt. Med hjälp av dess skript och MACRO-funktional...
Hur man visar FPS-räknare i Linux-spel
Linux-spel fick ett stort tryck när Valve tillkännagav Linux-stöd för Steam-klient och deras spel 2012. Sedan dess har många AAA- och indiespel tagit ...