Kaip naudotis signalų tvarkytojais C kalba?

How Use Signal Handlers C Language



Šiame straipsnyje mes parodysime, kaip naudoti signalų tvarkytojus „Linux“ naudojant C kalbą. Bet pirmiausia aptarsime, kas yra signalas, kaip jis generuos bendrus signalus, kuriuos galite naudoti savo programoje, o tada pažiūrėsime, kaip programa gali valdyti įvairius signalus, kol programa vykdoma. Taigi, pradėkime.

Signalas

Signalas yra įvykis, kuris sukuriamas pranešant procesui ar gijai apie tam tikrą svarbią situaciją. Kai procesas ar gija gauna signalą, procesas ar gija sustabdo tai, ką daro, ir imasi tam tikrų veiksmų. Signalas gali būti naudingas bendravimui tarp procesų.







Standartiniai signalai

Signalai yra apibrėžti antraštės faile signalas.h kaip makro konstanta. Signalo pavadinimas prasidėjo nuo SIG, o po to - trumpas signalo aprašymas. Taigi kiekvienas signalas turi unikalią skaitmeninę vertę. Jūsų programa visada turėtų naudoti signalų pavadinimą, o ne signalų numerį. Priežastis yra ta, kad signalo numeris gali skirtis priklausomai nuo sistemos, tačiau vardų reikšmė bus standartinė.



Makro NSIG yra bendras apibrėžtų signalų skaičius. Vertė NSIG yra vienas didesnis už bendrą nustatytų signalų skaičių (visi signalų numeriai skiriami iš eilės).



Toliau pateikiami standartiniai signalai.





Signalo pavadinimas apibūdinimas
SIGHUP Pakabinkite procesą. SIGHUP signalas naudojamas pranešti apie vartotojo terminalo atjungimą, galbūt dėl ​​to, kad nutrūksta nuotolinis ryšys arba jis nutrūksta.
SIGINT Nutraukite procesą. Kai vartotojas įveda simbolį INTR (paprastai Ctrl + C), siunčiamas SIGINT signalas.
SIGQUIT Nutraukite procesą. Kai vartotojas įveda QUIT simbolį (paprastai Ctrl + ), siunčiamas SIGQUIT signalas.
SEAL Neteisėtas nurodymas. Kai bandoma vykdyti šiukšles ar privilegijuotas instrukcijas, generuojamas SIGILL signalas. Be to, SIGILL gali būti generuojamas, kai kaminas perpildomas, arba kai sistemai kyla problemų naudojant signalų tvarkyklę.
SIGTRAP Pėdsakų spąstai. Nutraukimo taško instrukcija ir kita gaudymo instrukcija sugeneruos SIGTRAP signalą. Derintojas naudoja šį signalą.
SIGABRT Nutraukti. SIGABRT signalas generuojamas iškviečiant nutraukimo () funkciją. Šis signalas rodo klaidą, kurią aptinka pati programa ir apie kurią praneša nutraukimo () funkcijos iškvietimas.
SIGFPE Slankiojo kablelio išimtis. Kai įvyko mirtina aritmetinė klaida, generuojamas SIGFPE signalas.
SIGUSR1 ir SIGUSR2 SIGUSR1 ir SIGUSR2 signalai gali būti naudojami kaip norite. Naudinga parašyti jiems signalų tvarkytoją programoje, kuri gauna signalą paprastam tarpusavio bendravimui.

Numatytasis signalų veiksmas

Kiekvienas signalas turi numatytąjį veiksmą, vieną iš šių:

Terminas: Procesas bus nutrauktas.
Pagrindas: Procesas bus nutrauktas ir bus sukurtas pagrindinis iškelties failas.
Ignas: Procesas ignoruos signalą.
Sustabdyti: Procesas sustos.
Paskyra: Procesas ir toliau bus sustabdytas.



Numatytasis veiksmas gali būti pakeistas naudojant tvarkyklės funkciją. Kai kurių signalo numatytųjų veiksmų pakeisti negalima. SIGKILL ir SIGABRT signalo numatytųjų veiksmų negalima pakeisti ar ignoruoti.

Signalo tvarkymas

Jei procesas gauna signalą, procesas gali pasirinkti tokio tipo signalą. Procesas gali ignoruoti signalą, nurodyti apdorojimo funkciją arba priimti numatytąjį tokio tipo signalo veiksmą.

  • Jei nurodytas signalo veiksmas nepaisomas, signalas nedelsiant pašalinamas.
  • Programa gali užregistruoti tvarkyklės funkciją, naudodama tokią funkciją kaip signalą arba sigacija . Tai vadinama prižiūrėtoju, kuris sugauna signalą.
  • Jei signalas nebuvo nei tvarkomas, nei ignoruojamas, atliekamas jo numatytasis veiksmas.

Mes galime valdyti signalą naudodami signalą arba sigacija funkcija. Čia matome, kaip paprasčiausias signalas () funkcija naudojama signalams valdyti.

tarptsignalą() (tarptženklas, tuštuma (*funkcija)(tarpt))

The signalas () paskambins į funkcija funkcija, jei procesas gauna signalą ženklas . The signalas () grąžina rodyklę į funkciją funkcija jei pavyks arba grąžina klaidą į errno, o -1 -kitaip.

The funkcija rodyklė gali turėti tris reikšmes:

  1. SIG_DFL : Tai rodyklė į numatytąją sistemos funkciją SIG_DFL () , paskelbtas m h antraštės failas. Jis naudojamas numatytiesiems signalo veiksmams atlikti.
  2. SIG_IGN : Tai yra sistemos ignoravimo rodyklė SIG_IGN () , paskelbtas m h antraštės failas.
  3. Vartotojo apibrėžta tvarkyklės funkcijos rodyklė : Vartotojo apibrėžtas tvarkyklės funkcijos tipas yra negalioja (*) (int) , reiškia, grąžinimo tipas yra niekinis ir vienas int tipo argumentas.

Pagrindinio signalo tvarkyklės pavyzdys

#įtraukti
#įtraukti
#įtraukti
tuštumasig_handler(tarptženklas){

// Apdorojimo funkcijos grąžinimo tipas turi būti negaliojantis
printf (' nVidaus tvarkyklės funkcija n');
}

tarptpagrindinis(){
signalą(SIGINT,sig_handler); // Registro signalo tvarkytojas
dėl(tarpti=1;;i++){ //Begalinis ciklas
printf ('%d: Pagrindinė funkcija viduje n',i);
miegoti(1); // 1 sekundės vėlavimas
}
grįžti 0;
}

Pavyzdžio1.c išvesties ekrano kopijoje matome, kad pagrindinėje funkcijoje vykdoma begalinė kilpa. Kai vartotojas įvedė „Ctrl“+C, pagrindinės funkcijos vykdymas sustoja ir iškviečiama signalo apdorojimo funkcija. Baigus apdorojimo funkciją, pagrindinė funkcija vėl buvo vykdoma. Kai vartotojo tipas įvedė Ctrl+, procesas nutraukiamas.

Ignoruoti signalus pavyzdys

#įtraukti
#įtraukti
#įtraukti
tarptpagrindinis(){
signalą(SIGINT,SIG_IGN); // Registro signalo tvarkytojas, ignoruojantis signalą

dėl(tarpti=1;;i++){ //Begalinis ciklas
printf ('%d: Pagrindinė funkcija viduje n',i);
miegoti(1); // 1 sekundės vėlavimas
}
grįžti 0;
}

Čia tvarkyklės funkcija yra registruotis SIG_IGN () funkcija, ignoruojanti signalinį veiksmą. Taigi, kai vartotojas įvedė Ctrl+C, SIGINT signalas generuojamas, bet veiksmas ignoruojamas.

Perregistruoti signalų tvarkytojo pavyzdį

#įtraukti
#įtraukti
#įtraukti

tuštumasig_handler(tarptženklas){
printf (' nVidaus tvarkyklės funkcija n');
signalą(SIGINT,SIG_DFL); // Iš naujo užregistruoti signalo tvarkyklę numatytam veiksmui
}

tarptpagrindinis(){
signalą(SIGINT,sig_handler); // Registro signalo tvarkytojas
dėl(tarpti=1;;i++){ //Begalinis ciklas
printf ('%d: Pagrindinė funkcija viduje n',i);
miegoti(1); // 1 sekundės vėlavimas
}
grįžti 0;
}

Pavyzdžio3.c išvesties ekrano kopijoje matome, kad vartotojui pirmą kartą įvedus „Ctrl+C“, buvo paleista tvarkyklės funkcija. Naudodami tvarkyklės funkciją, signalų tvarkytojas vėl užsiregistruos SIG_DFL už numatytąjį signalo veiksmą. Kai vartotojas antrą kartą įvedė „Ctrl“+C, procesas nutraukiamas, o tai yra numatytasis veiksmas SIGINT signalą.

Siunčiami signalai:

Procesas taip pat gali aiškiai siųsti signalus sau ar kitam procesui. signalų siuntimo funkcija gali būti naudojama pakelti () ir nužudyti (). Abi funkcijos deklaruojamos signal.h antraštės faile.

tarpt pakelti (tarptženklas)

Pakelimo () funkcija, naudojama signalui siųsti ženklas skambinimo procesui (pačiam). Sėkmingai grąžina nulį, o jei nepavyksta - nulinę reikšmę.

tarptnužudyti(pid_t pid, tarptženklas)

Nužudymo funkcija naudojama signalui siųsti ženklas nurodytam procesui ar procesų grupei pid .

SIGUSR1 signalo tvarkyklės pavyzdys

#įtraukti
#įtraukti

tuštumasig_handler(tarptženklas){
printf („Vidaus tvarkyklės funkcija n');
}

tarptpagrindinis(){
signalą(SIGUSR1,sig_handler); // Registro signalo tvarkytojas
printf („Pagrindinė funkcija viduje n');
pakelti (SIGUSR1);
printf („Pagrindinė funkcija viduje n');
grįžti 0;
}

Čia procesas siunčia SIGUSR1 signalą sau, naudodamas funkciją lift ().

Pakelkite naudodami nužudymo pavyzdžio programą

#įtraukti
#įtraukti
#įtraukti
tuštumasig_handler(tarptženklas){
printf („Vidaus tvarkyklės funkcija n');
}

tarptpagrindinis(){
pid_t pid;
signalą(SIGUSR1,sig_handler); // Registro signalo tvarkytojas
printf („Pagrindinė funkcija viduje n');
pid=kvailas(); // Proceso ID
nužudyti(pid,SIGUSR1); // Siųsti SIGUSR1 sau
printf („Pagrindinė funkcija viduje n');
grįžti 0;
}

Čia siunčiamas procesas SIGUSR1 signalą sau naudojant nužudyti () funkcija. nusiminęs () naudojamas norint gauti proceso ID.

Kitame pavyzdyje pamatysime, kaip tėvų ir vaikų procesai bendrauja (tarpprocesinis bendravimas) naudojant nužudyti () ir signalo funkcija.

Tėvų ir vaikų bendravimas su signalais

#įtraukti
#įtraukti
#įtraukti
#įtraukti
tuštumasig_handler_parent(tarptženklas){
printf („Tėvas: gavo atsako signalą iš vaiko n');
}

tuštumasig_handler_child(tarptženklas){
printf („Vaikas: gavo signalą iš tėvų n');
miegoti(1);
nužudyti(nusiteikęs(),SIGUSR1);
}

tarptpagrindinis(){
pid_t pid;
jei((pid=šakutė())<0){
printf ('Šakutė nepavyko n');
išeiti (1);
}
/ * Vaiko procesas */
Kitas jei(pid==0){
signalą(SIGUSR1,sig_handler_child); // Registro signalo tvarkytojas
printf („Vaikas: laukia signalo n');
Pauzė();
}
/ * Tėvų procesas */
Kitas{
signalą(SIGUSR1,sig_handler_parent); // Registro signalo tvarkytojas
miegoti(1);
printf („Tėvas: siunčia signalą vaikui n');
nužudyti(pid,SIGUSR1);
printf („Tėvas: laukiu atsakymo n');
Pauzė();
}
grįžti 0;
}

Čia, šakutė () funkcija sukuria antrinį procesą ir grąžina nulį vaiko procesui ir vaiko proceso ID pagrindiniam procesui. Taigi, pid buvo patikrinta, kad nuspręstų tėvų ir vaikų procesas. Tėvų procese jis užmigdomas 1 sekundę, kad vaiko procesas galėtų užregistruoti signalo apdorojimo funkciją ir laukti signalo iš tėvų. Po 1 sekundės tėvų proceso siųsti SIGUSR1 signalą vaikui apdoroti ir laukti vaiko atsako signalo. Vaiko procese pirmiausia laukiama signalo iš tėvų, o kai signalas gaunamas, iškviečiama tvarkyklės funkcija. Iš apdorojimo funkcijos vaiko procesas siunčia kitą SIGUSR1 signalą tėvams. Čia getppid () Ši funkcija naudojama norint gauti pirminį proceso ID.

Išvada

Signalas „Linux“ yra didelė tema. Šiame straipsnyje mes matėme, kaip valdyti signalą nuo pačių pagrindinių, taip pat sužinojome, kaip signalas generuojamas, kaip procesas gali siųsti signalą sau ir kitam procesui, kaip signalas gali būti naudojamas tarpusavio bendravimui.