Jak používat obslužné rutiny signálu v jazyce C?

How Use Signal Handlers C Language



V tomto článku vám ukážeme, jak používat manipulátory signálu v Linuxu pomocí jazyka C. Nejprve však probereme, co je signál, jak bude generovat některé běžné signály, které můžete ve svém programu použít, a poté se podíváme na to, jak různé signály může program zpracovávat během provádění programu. Začněme tedy.

Signál

Signál je událost, která je generována k upozornění procesu nebo vlákna, že nastala nějaká důležitá situace. Když proces nebo vlákno přijme signál, proces nebo vlákno zastaví, co dělá, a provede nějakou akci. Signál může být užitečný pro meziprocesovou komunikaci.







Standardní signály

Signály jsou definovány v hlavičkovém souboru signál. h jako makro konstantu. Název signálu začínal SIG a následoval krátký popis signálu. Každý signál má tedy jedinečnou číselnou hodnotu. Váš program by měl vždy používat název signálů, nikoli číslo signálů. Důvodem je, že číslo signálu se může lišit podle systému, ale význam jmen bude standardní.



Makro NSIG je celkový počet definovaných signálů. Hodnota NSIG je o jedno větší než celkový počet definovaných signálů (všechna čísla signálů jsou přidělována postupně).



Níže jsou uvedeny standardní signály:





Jméno signálu Popis
PŘIPOJENÍ Zavěste proces. Signál SIGHUP se používá k hlášení odpojení uživatelského terminálu, pravděpodobně kvůli ztrátě nebo zavěšení vzdáleného připojení.
SIGINT Přerušte proces. Když uživatel zadá znak INTR (obvykle Ctrl + C), odešle se signál SIGINT.
SIGQUIT Ukončete proces. Když uživatel zadá znak QUIT (obvykle Ctrl + ), odešle se signál SIGQUIT.
TĚSNĚNÍ Nelegální instrukce. Při pokusu o provedení odpadků nebo privilegovaných instrukcí je vygenerován signál SIGILL. SIGILL lze také generovat při přetečení zásobníku nebo když má systém potíže se spuštěním obsluhy signálu.
SIGTRAP Stopová past. Instrukce zarážky a další instrukce pasti vygenerují signál SIGTRAP. Ladicí program používá tento signál.
SIGABRT Přerušit. Signál SIGABRT je generován při volání funkce abort (). Tento signál indikuje chybu, která je detekována samotným programem a hlášena voláním funkce abort ().
SIGFPE Výjimka s pohyblivou řádovou čárkou. Když dojde k fatální aritmetické chybě, generuje se signál SIGFPE.
SIGUSR1 a SIGUSR2 Signály SIGUSR1 a SIGUSR2 lze použít libovolně. Je užitečné pro ně napsat obslužný program signálu, který přijímá signál pro jednoduchou meziprocesovou komunikaci.

Výchozí akce signálů

Každý signál má výchozí akci, jednu z následujících:

Období: Proces bude ukončen.
Jádro: Proces bude ukončen a vytvoří se hlavní soubor s výpisem stavu paměti.
Ignorovat: Proces bude signál ignorovat.
Stop: Proces se zastaví.
Účet: Proces bude nadále zastaven.



Výchozí akci lze změnit pomocí funkce obsluhy. Výchozí akci některých signálů nelze změnit. SIGKILL a SIGABRT Výchozí akci signálu nelze změnit ani ignorovat.

Zpracování signálu

Pokud proces obdrží signál, proces má na výběr akci pro tento druh signálu. Proces může ignorovat signál, může určit funkci obslužné rutiny nebo přijmout výchozí akci pro tento druh signálu.

  • Pokud je zadaná akce pro signál ignorována, signál je okamžitě zahozen.
  • Program může zaregistrovat funkci obsluhy pomocí funkce, jako je signál nebo sigaction . Tomu se říká psovod, který zachytí signál.
  • Pokud signál nebyl zpracován ani ignorován, dojde k jeho výchozí akci.

Signál zvládneme pomocí signál nebo sigaction funkce. Zde vidíme, jak nejjednodušší signál() Funkce se používá pro zpracování signálů.

intsignál() (intpodepsat, prázdné (*funkce)(int))

The signál() zavolá funkce funkce, pokud proces přijímá signál podepsat . The signál() vrací ukazatel na funkci funkce v případě úspěchu nebo vrátí chybu errno a -1 jinak.

The funkce pointer může mít tři hodnoty:

  1. SIG_DFL : Je to ukazatel na výchozí funkci systému SIG_DFL () , deklarováno v h hlavičkový soubor. Slouží k provedení výchozí akce signálu.
  2. SIG_IGN : Je to ukazatel na funkci ignorování systému SIG_IGN () , deklarováno v h hlavičkový soubor.
  3. Uživatelem definovaný ukazatel funkce obsluhy : Uživatelem definovaný typ funkce obslužné rutiny je void (*) (int) , znamená, že návratový typ je neplatný a jeden argument typu int.

Základní obsluha signálu Příklad

#zahrnout
#zahrnout
#zahrnout
prázdnésig_handler(intpodepsat){

// Návratový typ funkce obslužné rutiny by měl být neplatný
printf (' nFunkce vnitřní obsluhy n');
}

inthlavní(){
signál(SIGINT,sig_handler); // Registrace obsluhy signálu
pro(int=1;;++){ //Nekonečná smyčka
printf ('%d: Uvnitř hlavní funkce n',);
spát(1); // Zpoždění na 1 sekundu
}
vrátit se 0;
}

Na snímku obrazovky výstupu z příkladu1.c vidíme, že v hlavní funkci se provádí nekonečná smyčka. Když uživatel zadá Ctrl+C, vyvolá se zastavení hlavní funkce a funkce obsluhy signálu. Po dokončení funkce obslužné rutiny se obnovilo provádění hlavní funkce. Když uživatel zadá Ctrl+, proces se ukončí.

Ignorovat signály

#zahrnout
#zahrnout
#zahrnout
inthlavní(){
signál(SIGINT,SIG_IGN); // Registrace obsluhy signálu pro ignorování signálu

pro(int=1;;++){ //Nekonečná smyčka
printf ('%d: Uvnitř hlavní funkce n',);
spát(1); // Zpoždění na 1 sekundu
}
vrátit se 0;
}

Zde je funkce obsluhy zaregistrována SIG_IGN () funkce pro ignorování akce signálu. Když tedy uživatel zadal Ctrl+C, SIGINT signál generuje, ale akce je ignorována.

Znovu zaregistrujte příklad obsluhy signálu

#zahrnout
#zahrnout
#zahrnout

prázdnésig_handler(intpodepsat){
printf (' nFunkce vnitřní obsluhy n');
signál(SIGINT,SIG_DFL); // Znovu zaregistrovat obslužný program signálu pro výchozí akci
}

inthlavní(){
signál(SIGINT,sig_handler); // Registrace obsluhy signálu
pro(int=1;;++){ //Nekonečná smyčka
printf ('%d: Uvnitř hlavní funkce n',);
spát(1); // Zpoždění na 1 sekundu
}
vrátit se 0;
}

Na snímku obrazovky výstupu příkladu3.c vidíme, že když uživatel poprvé zadal Ctrl+C, vyvolala se funkce obsluhy. Ve funkci obsluhy se obsluha signálu znovu zaregistruje SIG_DFL pro výchozí akci signálu. Když uživatel zadá Ctrl+C podruhé, proces je ukončen, což je výchozí akce SIGINT signál.

Odesílání signálů:

Proces také může explicitně vysílat signály sobě nebo jinému procesu. Pro odesílání signálů lze použít funkci raise () a kill (). Obě funkce jsou deklarovány v hlavičkovém souboru signal.h.

int vyzdvihnout (intpodepsat)

Funkce raise () použitá pro odesílání signálu podepsat do procesu volání (samotného). Pokud je úspěšný, vrátí nulu a pokud selže, nenulovou hodnotu.

intzabít(pid_t pid, intpodepsat)

Funkce zabití použitá pro odeslání signálu podepsat na proces nebo skupinu procesů specifikovanou pid .

Příklad obsluhy signálu SIGUSR1

#zahrnout
#zahrnout

prázdnésig_handler(intpodepsat){
printf ('Funkce vnitřní obsluhy.' n');
}

inthlavní(){
signál(SIGUSR1,sig_handler); // Registrace obsluhy signálu
printf („Uvnitř hlavní funkce n');
vyzdvihnout (SIGUSR1);
printf („Uvnitř hlavní funkce n');
vrátit se 0;
}

Zde proces odesílá signál SIGUSR1 sobě pomocí funkce raise ().

Raise with Kill Example Program

#zahrnout
#zahrnout
#zahrnout
prázdnésig_handler(intpodepsat){
printf ('Funkce vnitřní obsluhy.' n');
}

inthlavní(){
pid_t pid;
signál(SIGUSR1,sig_handler); // Registrace obsluhy signálu
printf („Uvnitř hlavní funkce n');
pid=dostat se(); // Vlastní ID procesu
zabít(pid,SIGUSR1); // Pošlete SIGUSR1 sobě
printf („Uvnitř hlavní funkce n');
vrátit se 0;
}

Zde proces odeslat SIGUSR1 signál pro sebe pomocí zabít() funkce. getpid () slouží k získání samotného ID procesu.

V dalším příkladu uvidíme, jak nadřazené a podřízené procesy komunikují (Inter Process Communication) pomocí zabít() a signální funkce.

Komunikace rodičů se signály

#zahrnout
#zahrnout
#zahrnout
#zahrnout
prázdnésig_handler_parent(intpodepsat){
printf („Rodič: Dostal od dítěte signál odpovědi n');
}

prázdnésig_handler_child(intpodepsat){
printf („Dítě: Dostal signál od rodiče n');
spát(1);
zabít(getppid(),SIGUSR1);
}

inthlavní(){
pid_t pid;
-li((pid=Vidlička())<0){
printf ('Vidlice selhala.' n');
výstup (1);
}
/ * Podřízený proces */
jiný -li(pid==0){
signál(SIGUSR1,sig_handler_child); // Registrace obsluhy signálu
printf („Dítě: čeká na signál n');
pauza();
}
/ * Nadřazený proces */
jiný{
signál(SIGUSR1,sig_handler_parent); // Registrace obsluhy signálu
spát(1);
printf („Rodič: odesílání signálu dítěti n');
zabít(pid,SIGUSR1);
printf („Rodič: čeká na odpověď n');
pauza();
}
vrátit se 0;
}

Tady, Vidlička() funkce vytvoří podřízený proces a vrátí nulu do podřízeného procesu a ID podřízeného procesu do nadřazeného procesu. Pid byl tedy zkontrolován, aby rozhodl o procesu rodič a dítě. V rodičovském procesu je na 1 sekundu uspán, aby podřízený proces mohl zaregistrovat funkci obsluhy signálu a čekat na signál od rodiče. Po 1 sekundě rodičovský proces odešlete SIGUSR1 signál signálu pro dítě a počkejte na signál reakce od dítěte. V podřízeném procesu nejprve čeká na signál od rodiče a když je signál přijat, je vyvolána funkce obsluhy. Z funkce handleru podřízený proces odešle další SIGUSR1 signál rodiči. Tady getppid () funkce se používá pro získání ID nadřazeného procesu.

Závěr

Signál v Linuxu je velké téma. V tomto článku jsme viděli, jak zacházet se signálem od úplných základů, a také získat znalosti o tom, jak signál generovat, jak proces může posílat signál sobě samému a další proces, jak lze signál použít pro meziprocesovou komunikaci.