Hogyan kell használni a jelkezelőket C nyelven?

How Use Signal Handlers C Language



Ebben a cikkben megmutatjuk, hogyan kell használni a jelfeldolgozókat Linuxon C nyelv használatával. De először megvitatjuk, hogy mi a jel, hogyan generál néhány közös jelet, amelyeket felhasználhat a programjában, majd megvizsgáljuk, hogy a program hogyan tudja kezelni a különböző jeleket a program végrehajtása közben. Szóval, kezdjük.

Jel

A jel egy olyan esemény, amelyet azért hoznak létre, hogy értesítsenek egy folyamatot vagy szálat arról, hogy valamilyen fontos helyzet érkezett. Amikor egy folyamat vagy szál jelet kapott, a folyamat vagy szál leállítja a tevékenységét, és megtesz bizonyos lépéseket. A jel hasznos lehet a folyamatok közötti kommunikációban.







Standard jelek

A jeleket a fejlécfájl határozza meg jelzés.h makróállandóként. A jel neve SIG -vel kezdődik, majd a jel rövid leírása következik. Tehát minden jelnek egyedi számértéke van. A program mindig a jelek nevét használja, nem a jelek számát. Ennek oka az, hogy a jelszám rendszer szerint eltérő lehet, de a nevek jelentése szabványos lesz.



A makró NSIG a definiált jelek teljes száma. Az értéke NSIG eggyel nagyobb, mint a definiált összes jel (Minden jelszámot egymás után osztanak ki).



A szabványos jelek a következők:





Jel neve Leírás
SIGHUP Tegye le a folyamatot. A SIGHUP jel a felhasználói terminál szétkapcsolásának jelentésére szolgál, valószínűleg azért, mert egy távoli kapcsolat megszakad vagy leáll.
JEL A folyamat megszakítása. Amikor a felhasználó beírja az INTR karaktert (általában Ctrl + C), a rendszer elküldi a SIGINT jelet.
SIGQUIT Hagyja abba a folyamatot. Amikor a felhasználó beírja a QUIT karaktert (általában Ctrl + ), a SIGQUIT jel kerül elküldésre.
FÓKA Illegális utasítás. Amikor szemetet vagy kiváltságos utasítást próbál végrehajtani, a SIGILL jel generálódik. Ezenkívül a SIGILL akkor is előállítható, ha a verem túlcsordul, vagy ha a rendszernek problémái vannak a jelkezelő futtatásával.
SIGTRAP Nyomkövető csapda. Egy töréspont utasítás és más csapda utasítás generálja a SIGTRAP jelet. A hibakereső ezt a jelet használja.
SIGABRT Elvetél. A SIGABRT jel az abort () függvény meghívásakor keletkezik. Ez a jel azt a hibát jelzi, amelyet maga a program észlelt, és amelyet az abort () függvényhívás jelent.
SIGFPE Lebegőpontos kivétel. Végzetes számtani hiba esetén a SIGFPE jel generálódik.
SIGUSR1 és SIGUSR2 A SIGUSR1 és SIGUSR2 jelek tetszés szerint használhatók. Hasznos, ha jelfeldolgozót írunk nekik a programba, amely fogadja a jelet az egyszerű folyamatközi kommunikációhoz.

A jelek alapértelmezett művelete

Minden jelnek van egy alapértelmezett művelete, az alábbiak egyike:

Időtartam: A folyamat leáll.
Mag: A folyamat leáll, és létrehoz egy alapvető dump fájlt.
Ign: A folyamat figyelmen kívül hagyja a jelet.
Álljon meg: A folyamat leáll.
Fiók: A folyamat leállításától folytatódik.



Az alapértelmezett művelet megváltoztatható a kezelő funkcióval. Néhány jel alapértelmezett művelete nem módosítható. SIGKILL és SIGABRT a jel alapértelmezett művelete nem módosítható vagy figyelmen kívül hagyható.

Jelkezelés

Ha egy folyamat jelet kap, a folyamat választhat az adott jelhez tartozó cselekvéshez. A folyamat figyelmen kívül hagyhatja a jelet, megadhat egy kezelő funkciót, vagy elfogadhatja az alapértelmezett műveletet az ilyen típusú jelhez.

  • Ha a jel adott műveletét figyelmen kívül hagyja, akkor a jelet azonnal elveti.
  • A program regisztrálhat egy kezelő funkciót a funkció használatával, mint pl jel vagy sigaction . Ezt hívják kezelőnek, amely elkapja a jelet.
  • Ha a jelet nem kezelték és nem vették figyelmen kívül, akkor az alapértelmezett műveletre kerül sor.

A jelet a segítségével kezelhetjük jel vagy sigaction funkció. Itt láthatjuk, hogy a legegyszerűbb jel() funkció a jelek kezelésére szolgál.

intjel() (intjel, üres (*funkció)(int))

Az jel() hívni fogja a funkció funkció, ha a folyamat jelet kap jel . Az jel() mutatót ad vissza a függvényhez funkció ha sikeres, vagy hibát ad vissza errno -nak, és -1 -et.

Az funkció a mutatónak három értéke lehet:

  1. SIG_DFL : Ez egy mutató a rendszer alapértelmezett funkciójára SIG_DFL () , kijelentette h fejléc fájl. A jel alapértelmezett műveletének végrehajtására szolgál.
  2. SIG_IGN : Ez egy mutató a rendszer figyelmen kívül hagyására SIG_IGN () , kijelentette h fejléc fájl.
  3. A felhasználó által meghatározott kezelő funkciómutató : A felhasználó által meghatározott kezelő funkciótípus a érvénytelen (*) (int) , azt jelenti, hogy a visszatérési típus érvénytelen, és egy int típusú argumentum.

Alapvető jelkezelő példa

#befoglalni
#befoglalni
#befoglalni
üressig_handler(intjel){

// A kezelő függvény visszatérési típusának érvénytelennek kell lennie
printf (' nBelső kezelő funkció n');
}

intfő-(){
jel(JEL,sig_handler); // Regisztrációs jelkezelő
számára(intén=1;;én++){ // Végtelen ciklus
printf ('%d: Belül a fő funkció n',én);
alvás(1); // Késleltetés 1 másodpercig
}
Visszatérés 0;
}

A példa 1.c kimenetének képernyőképén láthatjuk, hogy a főfunkcióban végtelen ciklus fut. Amikor a felhasználó beírta a Ctrl+C billentyűt, a fő funkció végrehajtása leáll, és a jel kezelő funkciója meghívásra kerül. A kezelő funkció befejezése után a fő funkció végrehajtása folytatódott. Amikor a felhasználói típus beírta a Ctrl+ billentyűt, a folyamat kilép.

Példa a jelek figyelmen kívül hagyására

#befoglalni
#befoglalni
#befoglalni
intfő-(){
jel(JEL,SIG_IGN); // Regisztrálja a jelkezelőt a jel figyelmen kívül hagyására

számára(intén=1;;én++){ // Végtelen ciklus
printf ('%d: Belül a fő funkció n',én);
alvás(1); // Késleltetés 1 másodpercig
}
Visszatérés 0;
}

Itt a kezelő funkció a regisztráció SIG_IGN () funkció a jeltovábbítás figyelmen kívül hagyására. Tehát amikor a felhasználó beírta a Ctrl+C billentyűt, JEL jel generál, de a műveletet figyelmen kívül hagyja.

Példa az újraregisztrált jelkezelőre

#befoglalni
#befoglalni
#befoglalni

üressig_handler(intjel){
printf (' nBelső kezelő funkció n');
jel(JEL,SIG_DFL); // Regisztrálja újra a jelkezelőt az alapértelmezett művelethez
}

intfő-(){
jel(JEL,sig_handler); // Regisztrációs jelkezelő
számára(intén=1;;én++){ // Végtelen ciklus
printf ('%d: Belül a fő funkció n',én);
alvás(1); // Késleltetés 1 másodpercig
}
Visszatérés 0;
}

A példa 3.c kimenetének képernyőképén láthatjuk, hogy amikor a felhasználó először beírta a Ctrl+C billentyűt, a kezelő függvény meghívott. A kezelő funkcióban a jelkezelő újra regisztrál a SIG_DFL a jel alapértelmezett működéséhez. Amikor a felhasználó másodszor írta be a Ctrl+C billentyűt, a folyamat befejeződik, ami az alapértelmezett művelet JEL jel.

Jelzések küldése:

Egy folyamat kifejezetten jeleket is küldhet magának vagy egy másik folyamatnak. az emelési () és a kill () függvény használható jelek küldésére. Mindkét funkciót a signal.h fejlécfájl tartalmazza.

int emel (intjel)

A jel küldésére használt emelési () függvény jel a hívási folyamathoz (magához). Ha sikeres, akkor nullát ad vissza, és ha nem, nulla értéket ad vissza.

intmegöl(pid_t pid, intjel)

A jel küldésére használt kill funkció jel által meghatározott folyamathoz vagy folyamatcsoporthoz pid .

Példa a SIGUSR1 jelkezelőre

#befoglalni
#befoglalni

üressig_handler(intjel){
printf ('Belső kezelő funkció n');
}

intfő-(){
jel(SIGUSR1,sig_handler); // Regisztrációs jelkezelő
printf ('Belül a fő funkció n');
emel (SIGUSR1);
printf ('Belül a fő funkció n');
Visszatérés 0;
}

Itt a folyamat SIGUSR1 jelet küld magának a raise () függvény használatával.

Emelj Kill Example Programmal

#befoglalni
#befoglalni
#befoglalni
üressig_handler(intjel){
printf ('Belső kezelő funkció n');
}

intfő-(){
pid_t pid;
jel(SIGUSR1,sig_handler); // Regisztrációs jelkezelő
printf ('Belül a fő funkció n');
pid=hülye(); // Folyamat azonosítója
megöl(pid,SIGUSR1); // Küldje el magának a SIGUSR1 -et
printf ('Belül a fő funkció n');
Visszatérés 0;
}

Itt a folyamat küld SIGUSR1 jelzi önmagának a használatával megöl() funkció. hülye () a folyamat azonosítójának lekérésére szolgál.

A következő példában látni fogjuk, hogyan kommunikálnak a szülő és a gyermek folyamatai (Inter Process Communication) megöl() és jel funkció.

Szülő gyermek kommunikáció jelekkel

#befoglalni
#befoglalni
#befoglalni
#befoglalni
üressig_handler_parent(intjel){
printf ('Szülő: Válaszjelet kapott a gyerektől n');
}

üressig_handler_child(intjel){
printf ('Gyermek: Jelt kapott a szülőktől n');
alvás(1);
megöl(kapaszkodó(),SIGUSR1);
}

intfő-(){
pid_t pid;
ha((pid=Villa())<0){
printf ('Nem sikerült a villa n');
kijárat (1);
}
/ * Gyermekfolyamat */
más ha(pid==0){
jel(SIGUSR1,sig_handler_child); // Regisztrációs jelkezelő
printf ('Gyermek: jelre vár n');
szünet();
}
/ * Szülői folyamat */
más{
jel(SIGUSR1,sig_handler_parent); // Regisztrációs jelkezelő
alvás(1);
printf ('Szülő: jelet küld gyermeknek n');
megöl(pid,SIGUSR1);
printf ('Szülő: válaszra vár n');
szünet();
}
Visszatérés 0;
}

Itt, Villa() függvény létrehozza a gyermekfolyamatot, és nullát ad vissza a gyermekfolyamatnak, és a gyermekfolyamat -azonosítót a szülői folyamatnak. Tehát a pid ellenőrzésre került, hogy eldöntse a szülő és a gyermek folyamatát. A szülői folyamatban 1 másodpercig alszik, hogy a gyermekfolyamat regisztrálja a jelfeldolgozó funkciót, és várja meg a szülő jeleit. 1 másodperces szülői folyamat után küldjön SIGUSR1 jelezze a gyermeknek a folyamatot, és várja meg a gyermek válaszjelét. A gyermekfolyamatban először a szülői jelre vár, és amikor jel érkezik, a kezelő funkció hívódik meg. A kezelő funkcióból a gyermekfolyamat küld egy másikat SIGUSR1 jelezni a szülőnek. Itt getppid () függvény a szülői folyamat azonosítójának lekérésére szolgál.

Következtetés

A jelzés Linuxon nagy téma. Ebben a cikkben láttuk, hogyan kell kezelni a jelet az alapoktól, és megismerhetjük azt is, hogy a jel hogyan keletkezik, hogyan küldhet egy folyamat jelet önmagának és más folyamatoknak, hogyan használható a jel a folyamatok közötti kommunikációhoz.