Kuidas kasutada signaalitöötlejaid C -keeles?

How Use Signal Handlers C Language



Selles artiklis näitame teile, kuidas kasutada signaalitöötlejaid Linuxis, kasutades C -keelt. Kuid kõigepealt arutame, mis on signaal, kuidas see genereerib ühiseid signaale, mida saate oma programmis kasutada, ja seejärel vaatame, kuidas programm saab programmi täitmise ajal käsitleda erinevaid signaale. Niisiis, alustame.

Signaal

Signaal on sündmus, mis genereeritakse protsessi või lõime teatamiseks mõne olulise olukorra saabumisest. Kui protsess või lõim on saanud signaali, peatab protsess või lõim oma tegevuse ja võtab teatud toiminguid. Signaal võib olla kasulik protsessidevahelises suhtluses.





Tavalised signaalid

Signaalid on määratletud päisefailis signaal.h makrokonstandina. Signaali nimi algas SIG -iga ja sellele järgnes signaali lühikirjeldus. Seega on igal signaalil ainulaadne numbriline väärtus. Teie programm peaks alati kasutama signaalide nime, mitte signaalide numbrit. Põhjus on selles, et signaali number võib olenevalt süsteemist erineda, kuid nimede tähendus on standardne.



Makro NSIG on määratletud signaalide koguarv. Väärtus NSIG on üks suurem kui määratletud signaalide koguarv (kõik signaalinumbrid eraldatakse järjest).



Tavalised signaalid on järgmised:





Signaali nimi Kirjeldus
SIGHUP Pange protsess kinni. SIGHUP -signaali kasutatakse kasutaja terminali lahtiühendamise teatamiseks, võib -olla seetõttu, et kaugühendus on katkenud või katkeb.
SIGINT Katkestage protsess. Kui kasutaja trükib INTR -märgi (tavaliselt Ctrl + C), saadetakse SIGINT -signaal.
SIGQUIT Lõpetage protsess. Kui kasutaja kirjutab märgi QUIT (tavaliselt Ctrl + ), saadetakse SIGQUIT -signaal.
SEAL Ebaseaduslik juhendamine. Kui proovitakse täita prügi või privilegeeritud käske, genereeritakse SIGILL -signaal. Samuti saab SIGILL -i genereerida virna ületäitumisel või kui süsteemil on probleeme signaalikäitleja käitamisega.
SIGTRAP Jälgimislõks. Katkestuspunkti käsk ja muu lõksu käsk genereerivad SIGTRAP -signaali. Silur kasutab seda signaali.
SIGABRT Katkesta. SIGABRT -signaal genereeritakse funktsiooni abort () kutsumisel. See signaal näitab tõrget, mille programm ise tuvastab ja millest loobub () funktsiooni kutsumine.
SIGFPE Ujukoma erand. Surmaga lõppenud aritmeetilise vea korral genereeritakse SIGFPE signaal.
SIGUSR1 ja SIGUSR2 Signaale SIGUSR1 ja SIGUSR2 võib kasutada vastavalt soovile. Nende jaoks on kasulik kirjutada signaalikäitleja programmi, mis võtab vastu signaali lihtsaks protsessidevaheliseks suhtluseks.

Signaalide vaiketoiming

Igal signaalil on vaiketoiming, üks järgmistest.

Termin: Protsess lõpetatakse.
Tuum: Protsess lõpetatakse ja luuakse põhiline prügifail.
Ign: Protsess ignoreerib signaali.
Peatus: Protsess peatub.
Konto: Protsess jätkub peatamisest.



Vaiketoimingut saab käitlejafunktsiooni abil muuta. Mõne signaali vaiketoimingut ei saa muuta. SIGKILL ja SIGABRT signaali vaiketoimingut ei saa muuta ega ignoreerida.

Signaali käsitlemine

Kui protsess saab signaali, on protsessil selle signaali jaoks toiming valida. Protsess võib signaali ignoreerida, määrata käitlejafunktsiooni või aktsepteerida seda tüüpi signaali vaiketoimingut.

  • Kui signaali määratud toimingut ignoreeritakse, visatakse signaal kohe kõrvale.
  • Programm saab registreerida käitleja funktsiooni, kasutades sellist funktsiooni nagu signaal või sigaction . Seda nimetatakse käitlejaks, kes püüab signaali kinni.
  • Kui signaali pole käsitletud ega ignoreeritud, toimub selle vaiketoiming.

Saame signaali käsitseda kasutades signaal või sigaction funktsiooni. Siin näeme, kuidas kõige lihtsam signaal() funktsiooni kasutatakse signaalide käsitlemiseks.

intsignaal() (intmärk, tühine (*funktsiooni)(int))

The signaal() helistab funktsiooni funktsiooni, kui protsess saab signaali märk . The signaal() tagastab funktsioonile kursori funktsiooni kui see õnnestub või tagastab vea veale ja muul juhul -1.

The funktsiooni kursoril võib olla kolm väärtust:

  1. SIG_DFL : See on osutaja süsteemi vaikimisi funktsioonile SIG_DFL () , kuulutas välja aastal h päisefail. Seda kasutatakse signaali vaiketoimingute tegemiseks.
  2. SIG_IGN : See on osutaja süsteemi ignoreerimise funktsioonile SIG_IGN () , kuulutas välja aastal h päisefail.
  3. Kasutaja määratud käitlejafunktsiooni osuti : Kasutaja määratud käitleja funktsiooni tüüp on tühine (*) (int) , tähendab, et tagastustüüp on tühine ja üks argument tüüpi int.

Põhiline signaalikäitleja näide

#kaasake
#kaasake
#kaasake
tühinesig_handler(intmärk){

// Käsitleja funktsiooni tagastustüüp peab olema tühine
printf (' nSisemine käepideme funktsioon n');
}

intpeamine(){
signaal(SIGINT,sig_handler); // Registreeri signaali käitleja
eest(inti=1;;i++){ // Lõpmatu silmus
printf ('%d: põhifunktsiooni sees n',i);
magama(1); // Viivitus 1 sekund
}
tagasi 0;
}

Näite 1.c väljundi ekraanipildil näeme, et põhifunktsioonis täidab lõpmatu silmus. Kui kasutaja sisestas Ctrl+C, peatub põhifunktsiooni täitmine ja käivitatakse signaali käitlejafunktsioon. Pärast käitlejafunktsiooni lõpetamist jätkati põhifunktsiooni täitmist. Kui kasutajatüüp sisestas Ctrl+, lõpetatakse protsess.

Signaalide ignoreerimise näide

#kaasake
#kaasake
#kaasake
intpeamine(){
signaal(SIGINT,SIG_IGN); // Registreeri signaalikäitleja signaali ignoreerimiseks

eest(inti=1;;i++){ // Lõpmatu silmus
printf ('%d: põhifunktsiooni sees n',i);
magama(1); // Viivitus 1 sekund
}
tagasi 0;
}

Siin on käitleja funktsioon registreeruda SIG_IGN () funktsioon signaalitoime ignoreerimiseks. Niisiis, kui kasutaja sisestas Ctrl+C, SIGINT signaal genereeritakse, kuid toimingut eiratakse.

Signaalikäitleja ümberregistreerimise näide

#kaasake
#kaasake
#kaasake

tühinesig_handler(intmärk){
printf (' nSisemine käepideme funktsioon n');
signaal(SIGINT,SIG_DFL); // Signaalikäitleja uuesti registreerimine vaiketoiminguks
}

intpeamine(){
signaal(SIGINT,sig_handler); // Registreeri signaali käitleja
eest(inti=1;;i++){ // Lõpmatu silmus
printf ('%d: põhifunktsiooni sees n',i);
magama(1); // Viivitus 1 sekund
}
tagasi 0;
}

Näite3.c väljundi ekraanipildil näeme, et kui kasutaja esimest korda tippis Ctrl+C, käivitati käitlejafunktsioon. Käitlejafunktsioonis registreerub signaalikäitleja uuesti SIG_DFL signaali vaikimisi toimimiseks. Kui kasutaja sisestas Ctrl+C teist korda, lõpetatakse protsess, mis on vaikimisi toiming SIGINT signaal.

Signaalide saatmine:

Protsess võib ka selgesõnaliselt saata signaale endale või teisele protsessile. tõsta () ja tappa () funktsiooni saab kasutada signaalide saatmiseks. Mõlemad funktsioonid on deklareeritud signaali.h päisefailis.

int tõsta (intmärk)

Signaali saatmiseks kasutatav tõste () funktsioon märk helistamisprotsessile (iseendale). See tagastab nulli, kui see õnnestub, ja nullist erineva väärtuse, kui see ebaõnnestub.

inttappa(pid_t pid, intmärk)

Signaali saatmiseks kasutatav tapmisfunktsioon märk määratud protsessile või protsessigrupile pid .

SIGUSR1 signaalikäitleja näide

#kaasake
#kaasake

tühinesig_handler(intmärk){
printf ('Sisemine käepideme funktsioon n');
}

intpeamine(){
signaal(SIGUSR1,sig_handler); // Registreeri signaali käitleja
printf („Põhifunktsioon sees n');
tõsta (SIGUSR1);
printf („Põhifunktsioon sees n');
tagasi 0;
}

Siin saadab protsess tõste () funktsiooni abil endale SIGUSR1 signaali.

Tõsta tapmise näiteprogrammiga

#kaasake
#kaasake
#kaasake
tühinesig_handler(intmärk){
printf ('Sisemine käepideme funktsioon n');
}

intpeamine(){
pid_t pid;
signaal(SIGUSR1,sig_handler); // Registreeri signaali käitleja
printf („Põhifunktsioon sees n');
pid=loll(); // Protsessi ID ise
tappa(pid,SIGUSR1); // Saada SIGUSR1 endale
printf („Põhifunktsioon sees n');
tagasi 0;
}

Siin saadetakse protsess SIGUSR1 signaali endale kasutades tappa () funktsiooni. loll () kasutatakse enda protsessi ID saamiseks.

Järgmises näites näeme, kuidas vanem ja laps töötlevad (protsessidevaheline suhtlus) kasutades tappa () ja signaalifunktsioon.

Vanemate ja laste suhtlemine signaalidega

#kaasake
#kaasake
#kaasake
#kaasake
tühinesig_handler_parent(intmärk){
printf ('Vanem: sai lapselt vastussignaali n');
}

tühinesig_handler_child(intmärk){
printf ('Laps: sai vanemalt signaali n');
magama(1);
tappa(äge(),SIGUSR1);
}

intpeamine(){
pid_t pid;
kui((pid=kahvel())<0){
printf ('Kahvel ebaõnnestus n');
väljumine (1);
}
/ * Lapseprotsess */
muidu kui(pid==0){
signaal(SIGUSR1,sig_handler_child); // Registreeri signaali käitleja
printf ('Laps: ootab signaali n');
paus();
}
/ * Vanemprotsess */
muidu{
signaal(SIGUSR1,sig_handler_parent); // Registreeri signaali käitleja
magama(1);
printf („Vanem: saadab lapsele signaali n');
tappa(pid,SIGUSR1);
printf ('Vanem: ootan vastust n');
paus();
}
tagasi 0;
}

Siin, kahvel () funktsioon loob alamprotsessi ja tagastab alamprotsessile nulli ning vanemprotsessile alamprotsessi ID. Niisiis, pid on kontrollitud, et otsustada vanema ja lapse protsessi üle. Vanemprotsessis on see 1 sekundi jooksul magatud, et lapsprotsess saaks registreerida signaalikäitleja funktsiooni ja oodata vanema signaali. Pärast 1 sekundi vanemprotsessi saatmine SIGUSR1 andke signaal lapsele ja oodake lapse vastussignaali. Lapseprotsessis ootab see esmalt vanema signaali ja signaali vastuvõtmisel käivitatakse käitleja funktsioon. Käitlejafunktsioonist saadab alamprotsess teise SIGUSR1 vanemale märku anda. Siin getppid () funktsiooni kasutatakse vanemprotsessi ID saamiseks.

Järeldus

Signaal Linuxis on suur teema. Selles artiklis oleme näinud, kuidas käsitleda signaali väga elementaarselt ja saada ka teadmisi, kuidas signaal genereeritakse, kuidas protsess saab signaali iseendale ja muule protsessile saata, kuidas saab signaali kasutada protsessidevahelises suhtluses.