Jel
A jel olyan esemény, amelyet azért generálnak, hogy értesítsék a folyamatot vagy a szálat arról, hogy valamilyen fontos helyzet érkezett. Amikor egy folyamat vagy egy szál jelet kapott, a folyamat vagy a szál leállítja a működését, és valamilyen műveletet végrehajt. A jel hasznos lehet a folyamatok közötti kommunikációhoz.
Standard jelek
A jeleket a fejlécfájl határozza meg jel.h mint makroállandó. A jel neve „SIG” -vel kezdődött, amelyet a jel rövid leírása követett. Tehát minden jelnek egyedi számértéke van. A programnak mindig a jelek nevét kell használnia, nem a jelek számát. Ennek oka az, hogy a jelek száma rendszerenként eltérhet, de a nevek jelentése standard lesz.
A makró NSIG a definiált jel teljes száma. Az értéke NSIG eggyel nagyobb, mint a megadott jel teljes száma (az összes jelszámot egymás után osztják ki).
A következők a standard jelek:
Jel neve | Leírás |
SIGHUP | Tegye le a folyamatot. A SIGHUP jel arra szolgál, hogy jelentse a felhasználó termináljának megszakadását, valószínűleg azért, mert egy távoli kapcsolat megszakadt vagy leteszi a kapcsolatot. |
JEL | Szakítsa meg a folyamatot. Amikor a felhasználó beírja az INTR karaktert (általában Ctrl + C), akkor a SIGINT jelet küldi. |
SIGQUIT | Lépjen ki a folyamatból. Amikor a felhasználó beírja a QUIT karaktert (általában Ctrl + \), akkor a SIGQUIT jelet küldi. |
SIGILL | Illegális utasítás. Ha szemetet vagy privilegizált utasítást próbál végrehajtani, akkor a SIGILL jel jön létre. A SIGILL akkor is létrehozható, amikor a verem túlcsordul, vagy ha a rendszernek problémái vannak egy jelkezelő futtatásával. |
SIGTRAP | Nyomcsapda. 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 akkor keletkezik, amikor az abort () függvényt meghívják. Ez a jel hibát jelez, amelyet maga a program észlelt, és amelyet az abort () függvényhívás jelentett. |
SIGFPE | Lebegőpontos kivétel. Végzetes számtani hiba esetén a SIGFPE jel jön létre. |
SIGUSR1 és SIGUSR2 | A SIGUSR1 és SIGUSR2 jelek tetszés szerint használhatók. Hasznos egy jelkezelőt írni nekik abba a programba, amely az egyszerű folyamatközi kommunikáció érdekében fogadja a jelet. |
A jelek alapértelmezett művelete
Minden jelnek van egy alapértelmezett művelete, a következők egyikével:
Időtartam: A folyamat befejeződik.
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.
Cont: A folyamat továbbra is leáll.
Az alapértelmezett művelet a kezelő funkcióval megváltoztatható. Egyes jelek 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, akkor a folyamatnak választania kell a műveletet az adott jelhez. A folyamat figyelmen kívül hagyhatja a jelet, meghatározhat egy kezelő funkciót, vagy elfogadhatja az ilyen jel alapértelmezett műveletét.
- Ha a jelre megadott műveletet figyelmen kívül hagyják, akkor a jelet azonnal elvetik.
- A program regisztrálhat egy kezelő funkciót, például jel vagy jelzés. Ezt úgy hívják, hogy egy kezelő elkapja a jelet.
- Ha a jelet nem kezelték és nem is hagyták figyelmen kívül, akkor az alapértelmezett műveletre kerül sor.
A jelet használhatjuk jel vagy jelzés funkció. Itt láthatjuk, hogy a legegyszerűbb jel() funkció a jelek kezelésére szolgál.
int jel () (int signum, void (* func) (int))A jel() felhívja a func funkció, ha a folyamat jelet kap signum. A jel() visszaad egy mutatót a működésére func ha sikeres, vagy hibát ad vissza az errno-ra, máskülönben -1-re.
A func A mutatónak három értéke lehet:
- SIG_DFL: Ez egy mutató a rendszer alapértelmezett funkciójára SIG_DFL (), -ban nyilatkozott h fejlécfájl. A jel alapértelmezett műveletére szolgál.
- SIG_IGN: Ez egy mutató a rendszer figyelmen kívül hagyására SIG_IGN (),-ban nyilatkozott h fejlécfájl.
- Felhasználó által meghatározott kezelő funkció mutató: A felhasználó által meghatározott kezelő funkció típusa érvénytelen (*) (int), azt jelenti, hogy a return típus érvénytelen, és az int típusú argumentum.
Alap jelfeldolgozó példa
#include#include
#include
void sig_handler (int signum)
// A handler függvény visszatérési típusának érvénytelennek kell lennie
printf ("\ nBelső kezelő funkció \ n");
int main ()
jel (SIGINT, sig_handler); // Jelkezelő regisztrálása
for (int i = 1 ;; i ++) // Végtelen hurok
printf ("% d: Inside main function \ n", i);
alvás (1); // Késleltetés 1 másodpercig
visszatér 0;
Az 1. példa kimenetének képernyőképén.c, láthatjuk, hogy a fő funkcióban végtelen ciklus hajt végre. Amikor a felhasználó beírta a Ctrl + C billentyűkombináció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ó írja be a Ctrl + \ parancsot, a folyamat befejeződik.
Figyelmen kívül hagyja a jeleket
#include#include
#include
int main ()
jel (SIGINT, SIG_IGN); // Jelzőkezelő regisztrálása a jel figyelmen kívül hagyása érdekében
for (int i = 1 ;; i ++) // Végtelen hurok
printf ("% d: Inside main function \ n", i);
alvás (1); // Késleltetés 1 másodpercig
visszatér 0;
Itt a kezelő funkció regisztrálva van SIG_IGN () funkció a jelzé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ódik, de a műveletet figyelmen kívül hagyják.
Újra regisztrálja a jelkezelő példát
#include#include
#include
void sig_handler (int signum)
printf ("\ nBelső kezelő funkció \ n");
jel (SIGINT, SIG_DFL); // Újra regisztrálja a jelkezelőt alapértelmezett műveletre
int main ()
jel (SIGINT, sig_handler); // Jelkezelő regisztrálása
for (int i = 1 ;; i ++) // Végtelen hurok
printf ("% d: Inside main function \ n", i);
alvás (1); // Késleltetés 1 másodpercig
visszatér 0;
A 3. példa kimenetének képernyőképén.c, láthatjuk, hogy amikor a felhasználó először beírta a Ctrl + C billentyűkombinációt, a kezelő függvény meghívásra került. A kezelő funkcióban a jelkezelő újra regisztrál SIG_DFL a jel alapértelmezett műveletéhez. Amikor a felhasználó másodszor írja be a Ctrl + C billentyűkombinációt, a folyamat befejeződik, amely az alapértelmezett művelete JEL jel.
Jelek küldése:
Egy folyamat kifejezetten jeleket is küldhet önmagának vagy egy másik folyamatnak. A raise () és kill () függvény használható jelek küldésére. Mindkét funkció jelben van deklarálva.h fejlécfájl.
int emelés (int signum)A jel küldéséhez használt emelés () funkció signum a hívási folyamathoz (magához). Ha sikeres, akkor nullát ad vissza, ha nem, akkor nem null értéket ad vissza.
int kill (pid_t pid, int signum)A kill funkció a jel küldésére szolgál signum által meghatározott folyamathoz vagy folyamatcsoporthoz pid.
SIGUSR1 jelkezelő példa
#include#include
void sig_handler (int signum)
printf ("Belső kezelő funkció \ n");
int main ()
jel (SIGUSR1, sig_handler); // Jelkezelő regisztrálása
printf ("Inside main function \ n");
emelés (SIGUSR1);
printf ("Inside main function \ n");
visszatér 0;
Itt a folyamat a SIGUSR1 jelet küldi magának a raise () függvény segítségével.
Emelés a Kill példaprogrammal
#include#include
#include
void sig_handler (int signum)
printf ("Belső kezelő funkció \ n");
int main ()
pid_t pid;
jel (SIGUSR1, sig_handler); // Jelkezelő regisztrálása
printf ("Inside main function \ n");
pid = getpid (); // Folyamatazonosítója
kill (pid, SIGUSR1); // Küldje el a SIGUSR1-et magának
printf ("Inside main function \ n");
visszatér 0;
Itt a folyamat küldés SIGUSR1 jelet magának felhasználásával megöl() funkció. getpid () a folyamatazonosító megszerzésére szolgál.
A következő példában megnézzük, hogy a szülő és a gyermek hogyan kommunikál (Inter Process Communication) megöl() és a jel funkció.
A szülő gyermek kommunikációja a jelekkel
#include#include
#include
#include
void sig_handler_parent (int signum)
printf ("Szülő: Válaszjelet kapott a gyermektől \ n");
void sig_handler_child (int signum)
printf ("Gyermek: Jelet kapott a szülőtől \ n");
alvás (1);
kill (getppid (), SIGUSR1);
int main ()
pid_t pid;
if ((pid = villa ())<0)
printf ("Sikertelen villa \ n");
kilépés (1);
/ * Gyermekfolyamat * /
else if (pid == 0)
jel (SIGUSR1, sig_handler_child); // Jelkezelő regisztrálása
printf ("Gyermek: jelre vár \ n");
szünet();
/ * Szülői folyamat * /
más
jel (SIGUSR1, sig_handler_szülő); // Jelkezelő regisztrálása
alvás (1);
printf ("Szülő: jel küldése Gyermeknek \ n");
kill (pid, SIGUSR1);
printf ("Szülő: válaszra vár \ n");
szünet();
visszatér 0;
Itt, Villa() függvény létrehozza a gyermek folyamatát, és nulla értéket ad vissza a gyermek folyamathoz, és a gyermek folyamat azonosítóját a szülő folyamathoz. Tehát, a pid ellenőrizte a szülő és a gyermek folyamatának eldöntését. A szülői folyamatban 1 másodpercig alszik, hogy a gyermek folyamat regisztrálja a jelkezelő funkciót, és megvárja a jelet a szülőtől. 1 másodperc után szülői folyamat küld SIGUSR1 jel a gyermeknek folyamat, és várja meg a gyermek válaszjelét. A gyermek folyamatban először a szülőktől érkező jelre vár, és amikor jel érkezik, a kezelő funkciót hívják meg. A kezelő funkcióból a gyermekfolyamat küld egy másikat SIGUSR1 jelzés a szülőnek. Itt getppid () függvény a szülő folyamatazonosító lekérésére szolgál.
Következtetés
A Linux alatt történő jelzés nagy téma. Ebben a cikkben láttuk, hogyan kell kezelni a jeleket az alapszinttől, és megismerhetjük azt is, hogy a jel hogyan keletkezik, hogyan képes egy folyamat jelet küldeni önmagának és más folyamatnak, hogyan lehet a jelet felhasználni a folyamatok közötti kommunikációra.