Kā lietot signālu apstrādātājus C valodā?

How Use Signal Handlers C Language



Šajā rakstā mēs jums parādīsim, kā izmantot signālu apstrādātājus Linux, izmantojot C valodu. Bet vispirms mēs apspriedīsim, kas ir signāls, kā tas ģenerēs dažus izplatītus signālus, kurus varat izmantot savā programmā, un pēc tam apskatīsim, kā programma var apstrādāt dažādus signālus programmas izpildes laikā. Tātad, sāksim.

Signāls

Signāls ir notikums, kas tiek ģenerēts, lai informētu procesu vai pavedienu, ka ir iestājusies kāda svarīga situācija. Kad process vai pavediens ir saņēmis signālu, process vai pavediens pārtrauks savu darbību un veiks kādu darbību. Signāls var būt noderīgs komunikācijai starp procesiem.







Standarta signāli

Signāli ir definēti galvenes failā signāls.h kā makro konstante. Signāla nosaukums ir sācies ar SIG un tam seko īss signāla apraksts. Tātad katram signālam ir unikāla skaitliska vērtība. Jūsu programmai vienmēr vajadzētu izmantot signālu nosaukumu, nevis signālu numuru. Iemesls ir signāla numurs atkarībā no sistēmas, taču vārdu nozīme būs standarta.



Makro NSIG ir kopējais definēto signālu skaits. Vērtība NSIG ir viens lielāks par kopējo definēto signālu skaitu (visi signālu numuri tiek piešķirti pēc kārtas).



Standarta signāli ir šādi:





Signāla nosaukums Apraksts
SIGHUP Pārtrauciet procesu. SIGHUP signāls tiek izmantots, lai ziņotu par lietotāja termināļa atvienošanu, iespējams, tāpēc, ka tiek zaudēts attālais savienojums vai tas pārtrauc klausuli.
SIGINT Pārtrauciet procesu. Kad lietotājs ievada INTR rakstzīmi (parasti Ctrl + C), tiek nosūtīts SIGINT signāls.
SIGQUIT Pārtrauciet procesu. Kad lietotājs ievada QUIT rakstzīmi (parasti Ctrl + ), tiek nosūtīts SIGQUIT signāls.
RONIS Nelegāla instrukcija. Mēģinot izpildīt atkritumus vai priviliģētas instrukcijas, tiek ģenerēts SIGILL signāls. Turklāt SIGILL var tikt ģenerēts, ja kaudze pārplūst vai ja sistēmai ir problēmas ar signālu apstrādātāja darbību.
SIGTRAP Izsekošanas slazds. Lūzuma punkta instrukcija un citas slazdošanas instrukcijas ģenerēs SIGTRAP signālu. Atkļūdotājs izmanto šo signālu.
SIGABRT Pārtraukt. SIGABRT signāls tiek ģenerēts, kad tiek izsaukta funkcija abort (). Šis signāls norāda uz kļūdu, ko atklāj pati programma un par ko ziņo pārtraukšanas () funkcijas izsaukums.
SIGFPE Peldošā komata izņēmums. Kad radās liktenīga aritmētiska kļūda, tiek ģenerēts SIGFPE signāls.
SIGUSR1 un SIGUSR2 Signālus SIGUSR1 un SIGUSR2 var izmantot, kā vēlaties. Ir lietderīgi viņiem ierakstīt signālu apstrādātāju programmā, kas saņem signālu vienkāršai starpprocesu saziņai.

Signālu noklusējuma darbība

Katram signālam ir noklusējuma darbība, viena no šīm darbībām:

Jēdziens: Process tiks pārtraukts.
Kodols: Process tiks pārtraukts un izveidos galveno izmetes failu.
Ign: Process ignorēs signālu.
Pietura: Process apstāsies.
Konts: Process tiks apturēts.



Noklusējuma darbību var mainīt, izmantojot apstrādātāja funkciju. Dažas signāla noklusējuma darbības nevar mainīt. SIGKILL un SIGABRT signāla noklusējuma darbību nevar mainīt vai ignorēt.

Signālu apstrāde

Ja process saņem signālu, tam ir iespēja izvēlēties šāda veida signālu. Process var ignorēt signālu, var norādīt apstrādātāja funkciju vai pieņemt noklusējuma darbību šāda veida signālam.

  • Ja norādītā signāla darbība tiek ignorēta, signāls tiek nekavējoties izmests.
  • Programma var reģistrēt apstrādātāja funkciju, izmantojot tādu funkciju kā signāls vai sigaction . To sauc par apstrādātāju, kas uztver signālu.
  • Ja signāls nav ne apstrādāts, ne ignorēts, tiek veikta tā noklusējuma darbība.

Mēs varam apstrādāt signālu, izmantojot signāls vai sigaction funkciju. Šeit mēs redzam, kā vienkāršākais signāls () funkcija tiek izmantota signālu apstrādei.

intsignāls() (intzīme, spēkā neesošs (*funkciju)(int))

The signāls () zvanīs uz funkciju funkciju, ja process saņem signālu zīme . The signāls () atgriež rādītāju funkcijai funkciju ja tas ir veiksmīgs vai tas atgriež kļūdu uz errno un -1 pretējā gadījumā.

The funkciju rādītājam var būt trīs vērtības:

  1. SIG_DFL : Tas ir rādītājs sistēmas noklusējuma funkcijai SIG_DFL () , deklarēts gadā h galvenes fails. To izmanto signāla noklusējuma darbību veikšanai.
  2. SIG_IGN : Tas ir rādītājs sistēmas ignorēšanas funkcijai SIG_IGN () , deklarēts gadā h galvenes fails.
  3. Lietotāja definēts apstrādātāja funkcijas rādītājs : Lietotāja definēts apstrādātāja funkcijas veids ir anulēts (*) (int) , nozīmē, ka atgriešanās veids nav derīgs, un viens argumenta veids int.

Signālu apstrādātāja pamata piemērs

#iekļaut
#iekļaut
#iekļaut
spēkā neesošssig_handler(intzīme){

// Apstrādātāja funkcijas atgriešanas veidam nav jābūt
printf (' nIekšējā apdarinātāja funkcija n');
}

intgalvenais(){
signāls(SIGINT,sig_handler); // Reģistra signālu apstrādātājs
priekš(inti=1;;i++){ // Bezgalīga cilpa
printf ('%d: galvenā funkcija iekšpusē n',i);
Gulēt(1); // Kavēšanās 1 sekundi
}
atgriezties 0;
}

Piemēra 1.c izvades ekrānuzņēmumā mēs redzam, ka galvenajā funkcijā tiek izpildīta bezgalīga cilpa. Kad lietotājs ievadīja taustiņu kombināciju Ctrl+C, galvenās funkcijas izpilde apstājās un tika izsaukta signāla apstrādātāja funkcija. Pēc apstrādātāja funkcijas pabeigšanas tika atsākta galvenās funkcijas izpilde. Kad lietotāja tips ierakstīja Ctrl+, process tiek pārtraukts.

Signālu ignorēšanas piemērs

#iekļaut
#iekļaut
#iekļaut
intgalvenais(){
signāls(SIGINT,SIG_IGN); // Reģistrēt signālu apstrādātāju signāla ignorēšanai

priekš(inti=1;;i++){ // Bezgalīga cilpa
printf ('%d: galvenā funkcija iekšpusē n',i);
Gulēt(1); // Kavēšanās 1 sekundi
}
atgriezties 0;
}

Šeit apstrādātāja funkcija ir reģistrēties SIG_IGN () funkcija signāla darbības ignorēšanai. Tātad, kad lietotājs ievadīja taustiņu kombināciju Ctrl+C, SIGINT signāls tiek ģenerēts, bet darbība tiek ignorēta.

Signāla apstrādātāja pārreģistrēšanas piemērs

#iekļaut
#iekļaut
#iekļaut

spēkā neesošssig_handler(intzīme){
printf (' nIekšējā apdarinātāja funkcija n');
signāls(SIGINT,SIG_DFL); // Pārreģistrēt signālu apstrādātāju noklusējuma darbībai
}

intgalvenais(){
signāls(SIGINT,sig_handler); // Reģistra signālu apstrādātājs
priekš(inti=1;;i++){ // Bezgalīga cilpa
printf ('%d: galvenā funkcija iekšpusē n',i);
Gulēt(1); // Kavēšanās 1 sekundi
}
atgriezties 0;
}

Piemēra3.c izvades ekrānuzņēmumā mēs redzam, ka tad, kad lietotājs pirmo reizi ierakstīja Ctrl+C, tika izsaukta apstrādātāja funkcija. Apstrādes funkcijā signālu apstrādātājs atkārtoti reģistrējas SIG_DFL signāla noklusējuma darbībai. Kad lietotājs otro reizi ierakstīja Ctrl+C, process tiek pārtraukts, kas ir noklusējuma darbība SIGINT signāls.

Signālu sūtīšana:

Process var arī skaidri nosūtīt signālus sev vai citam procesam. signālu nosūtīšanai var izmantot funkciju paaugstināt () un nogalināt (). Abas funkcijas tiek deklarētas signal.h galvenes failā.

int paaugstināt (intzīme)

Pacelšanas () funkcija, ko izmanto signāla nosūtīšanai zīme zvanīšanas procesam (pašam). Ja tas izdodas, tas atgriež nulli un vērtību, ja tas neizdodas.

intnogalināt(pid_t pid, intzīme)

Nogalināšanas funkcija, ko izmanto signāla nosūtīšanai zīme procesam vai procesu grupai, ko norādījis pid .

SIGUSR1 signālu apstrādātāja piemērs

#iekļaut
#iekļaut

spēkā neesošssig_handler(intzīme){
printf ('Iekšējā apdarinātāja funkcija n');
}

intgalvenais(){
signāls(SIGUSR1,sig_handler); // Reģistra signālu apstrādātājs
printf ('Galvenā funkcija iekšpusē n');
paaugstināt (SIGUSR1);
printf ('Galvenā funkcija iekšpusē n');
atgriezties 0;
}

Šeit process nosūta sev SIGUSR1 signālu, izmantojot funkciju lift ().

Paaugstiniet ar nogalināšanas piemēru programmu

#iekļaut
#iekļaut
#iekļaut
spēkā neesošssig_handler(intzīme){
printf ('Iekšējā apdarinātāja funkcija n');
}

intgalvenais(){
pid_t pid;
signāls(SIGUSR1,sig_handler); // Reģistra signālu apstrādātājs
printf ('Galvenā funkcija iekšpusē n');
pid=stulbs(); // Procesa ID
nogalināt(pid,SIGUSR1); // Sūtīt SIGUSR1 sev
printf ('Galvenā funkcija iekšpusē n');
atgriezties 0;
}

Lūk, process sūtīt SIGUSR1 signālu sev, izmantojot nogalināt () funkciju. traks () tiek izmantots, lai iegūtu procesa ID.

Nākamajā piemērā mēs redzēsim, kā vecāku un bērnu procesi sazinās (starpprocesu komunikācija), izmantojot nogalināt () un signāla funkcija.

Vecāku un bērnu komunikācija ar signāliem

#iekļaut
#iekļaut
#iekļaut
#iekļaut
spēkā neesošssig_handler_parent(intzīme){
printf ('Vecāks: saņēma atbildes signālu no bērna n');
}

spēkā neesošssig_handler_child(intzīme){
printf ('Bērns: saņēma signālu no vecākiem n');
Gulēt(1);
nogalināt(getppid(),SIGUSR1);
}

intgalvenais(){
pid_t pid;
ja((pid=dakša())<0){
printf ('Neizdevās dakša n');
Izeja (1);
}
/ * Bērnu process */
citādi ja(pid==0){
signāls(SIGUSR1,sig_handler_child); // Reģistra signālu apstrādātājs
printf ('Bērns: gaida signālu n');
pauze();
}
/ * Vecāku process */
citādi{
signāls(SIGUSR1,sig_handler_parent); // Reģistra signālu apstrādātājs
Gulēt(1);
printf ('Vecāks: sūta signālu bērnam n');
nogalināt(pid,SIGUSR1);
printf (Vecāks: gaida atbildi n');
pauze();
}
atgriezties 0;
}

Šeit, dakša () funkcija izveido bērnu procesu un atgriež nulli bērna procesam un bērna procesa ID vecāku procesam. Tātad, pid ir pārbaudīts, lai izlemtu vecāku un bērnu procesu. Vecāku procesā tas tiek nogulēts 1 sekundi, lai bērna process varētu reģistrēt signālu apstrādātāja funkciju un gaidīt signālu no vecākiem. Pēc 1 sekundes vecāku procesa nosūtīšanas SIGUSR1 signalizēt bērnam un gaidīt atbildes signālu no bērna. Bērna procesā vispirms tiek gaidīts signāls no vecākiem, un, saņemot signālu, tiek izsaukta apstrādātāja funkcija. No apstrādātāja funkcijas bērna process nosūta citu SIGUSR1 signāls vecākiem. Šeit getppid () funkcija tiek izmantota vecāku procesa ID iegūšanai.

Secinājums

Signāls Linux ir liela tēma. Šajā rakstā mēs esam redzējuši, kā rīkoties ar signālu no paša pamata, kā arī iegūt zināšanas par signāla ģenerēšanu, kā process var nosūtīt signālu sev un citam procesam, kā signālu var izmantot starpprocesu saziņai.