Ako používať signály v jazyku C?

How Use Signal Handlers C Language



V tomto článku vám ukážeme, ako používať popisovače signálu v systéme Linux pomocou jazyka C. Najprv však prediskutujeme, čo je signál, ako bude generovať niektoré bežné signály, ktoré môžete vo svojom programe použiť, a potom sa pozrieme na to, ako môže program počas vykonávania programu spracovávať rôzne signály. Začnime teda.

Signál

Signál je udalosť, ktorá sa generuje s cieľom informovať proces alebo vlákno, že prišla nejaká dôležitá situácia. Akonáhle proces alebo vlákno prijme signál, proces alebo vlákno zastaví, čo robí, a vykoná nejakú akciu. Signál môže byť užitočný pre medziprocesovú komunikáciu.







Štandardné signály

Signály sú definované v hlavičkovom súbore signál.h ako makro konštanta. Názov signálu začína znakom SIG a nasleduje krátky popis signálu. Každý signál má teda jedinečnú číselnú hodnotu. Váš program by mal vždy používať názov signálov, nie číslo signálu. Dôvodom je, že číslo signálu sa môže líšiť v závislosti od systému, ale význam mien bude štandardný.



Makro NSIG je celkový počet definovaných signálov. Hodnota NSIG je jedna väčšia ako celkový definovaný počet signálov (Všetky čísla signálov sú priradené postupne).



Nasledujú štandardné signály:





Meno signálu Popis
PRIPOJIŤ Zaveste proces. Signál SIGHUP sa používa na hlásenie odpojenia používateľského terminálu, pravdepodobne preto, že sa stratilo alebo zavesilo vzdialené pripojenie.
SIGINT Prerušte proces. Keď používateľ zadá znak INTR (zvyčajne Ctrl + C), odošle sa signál SIGINT.
SIGQUIT Ukončite proces. Keď používateľ zadá znak QUIT (zvyčajne Ctrl + ), odošle sa signál SIGQUIT.
TULEŇ Nelegálne poučenie. Keď sa pokúsite vykonať odpadky alebo privilegované inštrukcie, vygeneruje sa signál SIGILL. SIGILL je možné generovať aj vtedy, keď sa zásobník preplní alebo keď má systém problémy so spustením obsluhy signálu.
SIGTRAP Stopová pasca. Inštrukcia bodu prerušenia a iná inštrukcia pasce vygeneruje signál SIGTRAP. Ladiaci program používa tento signál.
SIGABRT Prerušiť. Signál SIGABRT sa generuje pri vyvolaní funkcie abort (). Tento signál indikuje chybu, ktorú zistil samotný program a hlási ho volanie funkcie abort ().
SIGFPE Výnimka s pohyblivou rádovou čiarkou. Keď dôjde k závažnej aritmetickej chybe, vygeneruje sa signál SIGFPE.
SIGUSR1 a SIGUSR2 Signály SIGUSR1 a SIGUSR2 je možné použiť ľubovoľne. Je užitočné zapísať pre nich obslužný program signálu do programu, ktorý prijíma signál pre jednoduchú medziprocesovú komunikáciu.

Predvolená akcia signálov

Každý signál má predvolenú akciu, jednu z nasledujúcich:

Termín: Proces sa ukončí.
Jadro: Proces sa ukončí a vytvorí sa hlavný súbor s výpisom pamäte.
Ignorovať: Proces bude signál ignorovať.
Zastaviť: Proces sa zastaví.
Účet: Proces bude aj naďalej pokračovať.



Predvolenú akciu je možné zmeniť pomocou funkcie obsluhy. Predvolenú akciu niektorých signálov nemožno zmeniť. SIGKILL a SIGABRT Predvolenú akciu signálu nemožno zmeniť ani ignorovať.

Manipulácia so signálom

Ak proces prijme signál, proces má na výber akciu pre tento druh signálu. Proces môže ignorovať signál, môže určiť funkciu obsluhy alebo prijať predvolenú akciu pre tento druh signálu.

  • Ak sa špecifikovaná akcia pre signál ignoruje, signál sa okamžite zahodí.
  • Program môže zaregistrovať funkciu obsluhy pomocou funkcie ako napr signál alebo sigakcia . Hovorí sa tomu, že psovod zachytáva signál.
  • Ak signál nebol spracovaný ani ignorovaný, dôjde k jeho predvolenej akcii.

Signál zvládneme pomocou signál alebo sigakcia funkciu. Tu vidíme, ako najjednoduchšie signál () Táto funkcia sa používa na spracovanie signálov.

intsignál() (intpodpísať, prázdny (*funkciu)(int))

The signál () zavolá na funkciu funkciu, ak proces prijíma signál podpísať . The signál () vráti ukazovateľ na funkciu funkciu ak je úspešný alebo vráti chybu errno a -1 inak.

The funkciu ukazovateľ môže mať tri hodnoty:

  1. SIG_DFL : Je to ukazovateľ na predvolenú funkciu systému SIG_DFL () , vyhlásené v h hlavičkový súbor. Slúži na vykonanie predvolenej akcie signálu.
  2. SIG_IGN : Je to funkcia smerujúca k ignorovaniu systému SIG_IGN () , vyhlásené v h hlavičkový súbor.
  3. Užívateľom definovaný ukazovateľ funkcie obsluhy : Užívateľom definovaný typ funkcie obsluhy je prázdny (*) (int) , znamená, že návratový typ je neplatný a jeden argument typu int.

Základný príklad obsluhy signálu

#zahrnúť
#zahrnúť
#zahrnúť
prázdnysig_handler(intpodpísať){

// Návratový typ funkcie obsluhy by mal byť neplatný
printf (' nVnútorná funkcia obsluhy n');
}

intHlavná(){
signál(SIGINT,sig_handler); // Registrácia obsluhy signálu
pre(inti=1;;i++){ //Nekonečná slučka
printf ('%d: Vnútri hlavnej funkcie n',i);
spať(1); // Meškanie 1 sekundu
}
vrátiť sa 0;
}

Na snímke obrazovky výstupu z príkladu1.c vidíme, že v hlavnej funkcii sa vykonáva nekonečná slučka. Keď používateľ zadá Ctrl+C, vyvolá sa zastavenie vykonávania hlavnej funkcie a obslužná funkcia signálu. Po dokončení funkcie obsluhy sa obnovilo vykonávanie hlavnej funkcie. Keď používateľ zadá klávesovú skratku Ctrl+, proces sa ukončí.

Ignorovať signály

#zahrnúť
#zahrnúť
#zahrnúť
intHlavná(){
signál(SIGINT,SIG_IGN); // Zaregistrujte obsluhu signálu pre ignorovanie signálu

pre(inti=1;;i++){ //Nekonečná slučka
printf ('%d: Vnútri hlavnej funkcie n',i);
spať(1); // Meškanie 1 sekundu
}
vrátiť sa 0;
}

Tu je funkcia obsluhy zaregistrovaná SIG_IGN () funkcia na ignorovanie akcie signálu. Keď teda používateľ zadal Ctrl+C, SIGINT signál sa generuje, ale akcia sa ignoruje.

Znovu zaregistrujte príklad obsluhy signálu

#zahrnúť
#zahrnúť
#zahrnúť

prázdnysig_handler(intpodpísať){
printf (' nVnútorná funkcia obsluhy n');
signál(SIGINT,SIG_DFL); // Znovu zaregistrovať obslužný program signálu na predvolenú akciu
}

intHlavná(){
signál(SIGINT,sig_handler); // Registrácia obsluhy signálu
pre(inti=1;;i++){ //Nekonečná slučka
printf ('%d: Vnútri hlavnej funkcie n',i);
spať(1); // Meškanie 1 sekundu
}
vrátiť sa 0;
}

Na snímke obrazovky výstupu z príkladu3.c vidíme, že keď používateľ prvýkrát zadal Ctrl+C, vyvolala sa funkcia obsluhy. Vo funkcii obsluhy sa obsluha signálu znova zaregistruje na SIG_DFL pre predvolenú akciu signálu. Keď používateľ zadá druhýkrát Ctrl+C, proces sa ukončí, čo je predvolená akcia SIGINT signál.

Odosielanie signálov:

Proces môže tiež explicitne vysielať signály sebe alebo inému procesu. Na odosielanie signálov je možné použiť funkciu raise () a kill (). Obe funkcie sú deklarované v hlavičkovom súbore signal.h.

int zdvihnúť (intpodpísať)

Funkcia raise () používaná na odosielanie signálu podpísať do procesu volania (samotného). V prípade úspechu vráti nulu a v prípade zlyhania nenulovú hodnotu.

intzabiť(pid_t pid, intpodpísať)

Funkcia zabitia použitá na odoslanie signálu podpísať do procesu alebo skupiny procesov určenej pid .

Príklad obsluhy signálu SIGUSR1

#zahrnúť
#zahrnúť

prázdnysig_handler(intpodpísať){
printf („Vnútorná funkcia obsluhy n');
}

intHlavná(){
signál(SIGUSR1,sig_handler); // Registrácia obsluhy signálu
printf („Vnútri hlavnej funkcie n');
zdvihnúť (SIGUSR1);
printf („Vnútri hlavnej funkcie n');
vrátiť sa 0;
}

Tu proces pošle signál SIGUSR1 sebe pomocou funkcie raise ().

Raise with Kill Example Program

#zahrnúť
#zahrnúť
#zahrnúť
prázdnysig_handler(intpodpísať){
printf („Vnútorná funkcia obsluhy n');
}

intHlavná(){
pid_t pid;
signál(SIGUSR1,sig_handler); // Registrácia obsluhy signálu
printf („Vnútri hlavnej funkcie n');
pid=dostať sa(); // ID procesu
zabiť(pid,SIGUSR1); // Pošlite SIGUSR1 sebe
printf („Vnútri hlavnej funkcie n');
vrátiť sa 0;
}

Tu je postup odoslaný SIGUSR1 signál pre seba pomocou zabiť () funkciu. getpid () sa používa na získanie samotného ID procesu.

V nasledujúcom príklade uvidíme, ako nadradený a podradený proces komunikuje (medziprocesová komunikácia) pomocou zabiť () a signálna funkcia.

Komunikácia rodiča a dieťaťa so signálmi

#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť
prázdnysig_handler_parent(intpodpísať){
printf („Rodič: Dostal signál reakcie od dieťaťa n');
}

prázdnysig_handler_child(intpodpísať){
printf („Dieťa: Dostal signál od rodiča n');
spať(1);
zabiť(getppid(),SIGUSR1);
}

intHlavná(){
pid_t pid;
keby((pid=vidlička())<0){
printf („Vidlica zlyhala n');
východ (1);
}
/ * Detský proces */
inak keby(pid==0){
signál(SIGUSR1,sig_handler_child); // Registrácia obsluhy signálu
printf („Dieťa: čaká na signál n');
pauza();
}
/ * Rodičovský proces */
inak{
signál(SIGUSR1,sig_handler_parent); // Registrácia obsluhy signálu
spať(1);
printf („Rodič: odosielanie signálu dieťaťu n');
zabiť(pid,SIGUSR1);
printf („Rodič: čakám na odpoveď n');
pauza();
}
vrátiť sa 0;
}

Tu, vidlička() funkcia vytvorí podradený proces a vráti nulu do podradeného procesu a ID podradeného procesu do nadradeného procesu. Pid bol teda skontrolovaný, aby sa rozhodol proces rodič a dieťa. V rodičovskom procese je spánok na 1 sekundu, aby podradený proces mohol zaregistrovať funkciu obsluhy signálu a čakať na signál od rodiča. Po 1 sekunde odošlite rodičovský proces SIGUSR1 signál signál dieťaťu a počkajte na signál reakcie dieťaťa. V detskom procese najskôr čaká na signál od rodiča a keď je signál prijatý, je vyvolaná funkcia obsluhy. Z funkcie handler podradený proces odošle ďalší SIGUSR1 signál rodičovi. Tu getppid () funkcia sa používa na získanie ID rodičovského procesu.

Záver

Signál v Linuxe je veľká téma. V tomto článku sme videli, ako zvládnuť signál od základov, a taktiež sme získali znalosti o tom, ako signál generuje, ako môže proces odosielať signál sebe a iným procesom, ako je možné signál použiť na medziprocesovú komunikáciu.