C Programmeerimine

Kuidas kasutada signaalkäitlejaid C-keeles?

Kuidas kasutada signaalkäitlejaid C-keeles?
Selles artiklis me näitame teile, kuidas kasutada Linuxis signaalkäitlejaid C-keele abil. Kuid kõigepealt arutame, mis on signaal, kuidas see genereerib mõned levinumad signaalid, mida saate oma programmis kasutada, ja siis vaatame, kuidas programm saab erinevaid signaale hallata, kui programm käivitub. Alustame siis.

Signaal

Signaal on sündmus, mis genereeritakse protsessi või lõime teavitamiseks mõne olulise olukorra saabumisest. Kui protsess või lõim on signaali saanud, peatab protsess või lõim oma tegevuse ja võtab mõne toimingu. Signaal võib olla kasulik protsessidevaheliseks suhtlemiseks.

Standardsignaalid

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

Makro NSIG on määratletud signaali koguarv. Väärtus NSIG on üks suurem kui määratletud signaali koguarv (kõik signaalinumbrid jagatakse järjestikku).

Järgmised on standardsignaalid:

Signaali nimi Kirjeldus
SIGHUP Katkestage protsess. Signaali SIGHUP kasutatakse kasutaja terminali lahtiühendamisest teatamiseks, võib-olla seetõttu, et kaugühendus on kadunud või katkestab ühenduse.
SIGINT Katkestage protsess. Kui kasutaja sisestab märgi INTR (tavaliselt Ctrl + C), saadetakse signaal SIGINT.
SIGQUIT Lõpeta protsess. Kui kasutaja sisestab märgi QUIT (tavaliselt Ctrl + \), saadetakse signaal SIGQUIT.
SIGILL Ebaseaduslik juhendamine. Kui proovitakse täita prügi või privilegeeritud juhiseid, genereeritakse signaal SIGILL. Samuti saab SIGILL-i genereerida virna ülevoolamisel või kui süsteemil on probleeme signaalkäitleja käitamisega.
SIGTRAP Jäljepüünis. Murdepunkti käsk ja muud püünisjuhised genereerivad SIGTRAP signaali. Silur kasutab seda signaali.
SIGABRT Katkesta. Signaal SIGABRT genereeritakse, kui kutsutakse funktsioon abort (). See signaal näitab viga, mille programm ise tuvastab ja mille funktsioonikõne abort () teatab.
SIGFPE Ujuvate punktide erand. Saatusliku aritmeetilise vea tekkimisel genereeritakse signaal SIGFPE.
SIGUSR1 ja SIGUSR2 Signaale SIGUSR1 ja SIGUSR2 võidakse kasutada vastavalt teie soovile. Nende jaoks on kasulik kirjutada signaalkäitleja programmis, mis võtab signaali vastu lihtsaks protsessidevaheliseks suhtlemiseks.

Signaalide vaiketoiming

Igal signaalil on vaiketoiming, üks järgmistest:

Termin: Protsess lõpeb.
Tuum: Protsess lõpetatakse ja luuakse tuumafail.
Ign: Protsess ignoreerib signaali.
Peatus: Protsess peatub.
Cont: Protsessi peatamine jätkub.

Vaiketoimingut saab muuta käitleja funktsiooni abil. Mõne signaali vaiketoimingut ei saa muuta. SIGKILL ja SIGABRT signaali vaiketoimingut ei saa muuta ega eirata.

Signaali käsitsemine

Kui protsess saab signaali, saab protsess seda tüüpi signaali jaoks valida toimingu. Protsess võib signaali ignoreerida, määrata käitleja funktsiooni või aktsepteerida sellist signaali vaiketoimingut.

Saame signaaliga hakkama signaal või sigaction funktsioon. Siin näeme, kuidas kõige lihtsam signaal() funktsiooni kasutatakse signaalide käitlemiseks.

int signaal () (int signum, tühine (* func) (int))

The signaal() helistab func funktsioon, kui protsess saab signaali signum. The signaal() tagastab kursori funktsiooni func kui see õnnestub või tagastab vea vigale ja muul juhul -1.

The func osutil võib olla kolm väärtust:

  1. SIG_DFL: See näitab süsteemi vaikefunktsiooni SIG_DFL (), aastal deklareeritud h päisefail. Seda kasutatakse signaali vaiketoimingute tegemiseks.
  2. SIG_IGN: See on osutus süsteemi ignoreerimiseks SIG_IGN (),aastal deklareeritud h päisefail.
  3. Kasutaja määratud käitleja funktsioonikursor: Kasutaja määratud käitleja funktsiooni tüüp on kehtetu (*) (int), tähendab, et tagasitüübi tüüp on tühine ja üks argumendi tüüp int.

Signaali käitleja põhinäide

# kaasata
# kaasata
# kaasata
void sig_handler (int signum)
// Handleri funktsiooni Return tüüp peaks olema tühine
printf ("\ nSisese käitleja funktsioon \ n");

int main ()
signaal (SIGINT, sig_handler); // Registreerige signaalkäitleja
for (int i = 1 ;; i ++) // lõpmatu silmus
printf ("% d: sees põhifunktsioon \ n", i);
uni (1); // Viivitage 1 sekund

tagastama 0;

Näite1 väljundi ekraanipildil.c, näeme, et põhifunktsioonis käivitab lõpmatu silmus. Kui kasutaja sisestas Ctrl + C, peatub põhifunktsiooni täitmine ja käivitatakse signaali käitlejafunktsioon. Pärast käitleja funktsiooni täitmist jätkati põhifunktsiooni täitmist. Kui kasutaja tüüp sisestas Ctrl + \, protsess lõpetatakse.

Eirake signaali näidet

# kaasata
# kaasata
# kaasata
int main ()
signaal (SIGINT, SIG_IGN); // Registreerige signaali käitleja signaali eiramiseks
for (int i = 1 ;; i ++) // lõpmatu silmus
printf ("% d: sees põhifunktsioon \ n", i);
uni (1); // Viivitage 1 sekund

tagastama 0;

Siin on käitleja funktsioon registreerida SIG_IGN () funktsioon signaali toimingu ignoreerimiseks. Niisiis, kui kasutaja sisestas Ctrl + C,  SIGINT signaal genereeritakse, kuid toimingut ignoreeritakse.

Signalinkäitleja näide uuesti registreerimine

# kaasata
# kaasata
# kaasata
void sig_handler (int signum)
printf ("\ nSisese käitleja funktsioon \ n");
signaal (SIGINT, SIG_DFL); // Registreerige signaalitöötleja uuesti vaiketoiminguks

int main ()
signaal (SIGINT, sig_handler); // Registreerige signaalkäitleja
for (int i = 1 ;; i ++) // lõpmatu silmus
printf ("% d: sees põhifunktsioon \ n", i);
uni (1); // Viivitage 1 sekund

tagastama 0;

Näite 3 väljundi ekraanipildil.c, näeme, et kui kasutaja sisestas esmakordselt Ctrl + C, kutsuti üles käitleja funktsioon. Käitleja funktsioonis registreerub signaalikäitleja uuesti SIG_DFL signaali vaiketoimingu jaoks. Kui kasutaja sisestas teist korda klahvikombinatsiooni Ctrl + C, lõpetatakse protsess, mis on faili vaiketoiming SIGINT signaal.

Signaalide saatmine:

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

int tõsta (int signum)

Signaali saatmiseks kasutatav funktsioon lift () signum helistamisprotsessile (iseendale). See tagastab õnnestumise korral nulli ja ebaõnnestumise korral nullväärtuse.

int tapma (pid_t pid, int signum)

Tapmise funktsioon, mida kasutatakse signaali saatmiseks signum määratud protsessile või protsessigrupile pid.

SIGUSR1 signaalkäitleja näide

# kaasata
# kaasata
void sig_handler (int signum)
printf ("Sisemise käitleja funktsioon \ n");

int main ()
signaal (SIGUSR1, sig_handler); // Registreerige signaalkäitleja
printf ("Sees põhifunktsioon \ n");
tõsta (SIGUSR1);
printf ("Sees põhifunktsioon \ n");
tagastama 0;

Siin saadab protsess SIGUSR1 signaali endale, kasutades funktsiooni raise ().

Tõstke Kill Näidisprogrammiga

# kaasata
# kaasata
# kaasata
void sig_handler (int signum)
printf ("Sisemise käitleja funktsioon \ n");

int main ()
pid_t pid;
signaal (SIGUSR1, sig_handler); // Registreerige signaalkäitleja
printf ("Sees põhifunktsioon \ n");
pid = getpid (); // Protsessi ID ise
tapma (pid, SIGUSR1); // Saada SIGUSR1 iseendale
printf ("Sees põhifunktsioon \ n");
tagastama 0;

Siin protsess saadetakse SIGUSR1 signaali endale kasutades tapma () funktsioon. getpid () kasutatakse enda protsessi ID saamiseks.

Järgmises näites näeme, kuidas vanema ja lapse protsessid suhtlevad (protsessidevaheline suhtlus) tapma () ja signaali funktsioon.

Vanemlapse suhtlus signaalidega

# kaasata
# kaasata
# kaasata
# kaasata
void sig_handler_parent (int signum)
printf ("Vanem: sai lapselt vastussignaali \ n");

void sig_handler_child (int signum)
printf ("Laps: sai vanemalt signaali \ n");
uni (1);
tapma (getppid (), SIGUSR1);

int main ()
pid_t pid;
kui ((pid = kahvel ())<0)
printf ("Kahvel ebaõnnestus \ n");
väljapääs (1);

/ * Lapse protsess * /
muidu if (pid == 0)
signaal (SIGUSR1, sig_handler_child); // Registreerige signaalkäitleja
printf ("Laps: ootab signaali \ n");
paus ();

/ * Vanemprotsess * /
veel
signaal (SIGUSR1, sig_handler_vanem); // Registreerige signaalkäitleja
uni (1);
printf ("Vanem: signaali saatmine lapsele \ n");
tapma (pid, SIGUSR1);
printf ("Vanem: ootab vastust \ n");
paus ();

tagastama 0;

Siin, kahvel () Funktsioon loob lapseprotsessi ja tagastab lapseprotsessile nulli ja lapseprotsessi ID vanemprotsessile. Niisiis, pid on kontrollitud, et otsustada vanema ja lapse protsess. Vanemprotsessis magatakse seda 1 sekund, et lapsprotsess saaks registreerida signaalkäitleja funktsiooni ja oodata vanema signaali. Pärast 1 sekundit vanemprotsessi saatmine SIGUSR1 signaal lapsele ja oodake lapse reageerimissignaali. Lapseprotsessis ootab see kõigepealt vanema signaali ja signaali vastuvõtmisel käivitatakse käitleja funktsioon. Käitleja funktsioonist saadab lapseprotsess teise SIGUSR1 signaal vanemale. Siin getppid () funktsiooni kasutatakse vanemprotsessi ID hankimiseks.

Järeldus

Signaal Linuxis on suur teema. Selles artiklis oleme näinud, kuidas käsitseda signaali kõige põhilisemast, ning saada ka teadmisi signaali genereerimise kohta, kuidas protsess saab signaali saata iseendale ja muule protsessile, kuidas signaali saab kasutada protsessidevaheliseks suhtluseks.

Kuidas näidata FPS-loendurit Linuxi mängudes
Linuxi mängimine sai suure tõuke, kui Valve teatas Steam-kliendi ja nende mängude Linuxi toest 2012. aastal. Sellest ajast peale on paljud AAA- ja ind...
Sid Meieri Civilization VI allalaadimine ja mängimine Linuxis
Sissejuhatus mängu Civilization 6 on kaasaegne kontseptsioon, mis tutvustati Age of Empires mängude sarjas. Idee oli üsna lihtne; alustaksite kõige põ...
Kuidas installida ja mängida Doomi Linuxis
Doomi sissejuhatus Doom-seeria sai alguse 90ndatel pärast algse Doomi väljaandmist. See oli kohene hitt ja sellest ajast alates on mänguseeria pälvinu...