C Programování

Jak používat manipulátory signálu v jazyce C?

Jak používat manipulátory signálu v jazyce C?
V tomto článku vám ukážeme, jak používat obslužné rutiny signálu v Linuxu pomocí jazyka C. Nejprve ale probereme, co je to signál, jak bude generovat některé běžné signály, které můžete použít ve svém programu, a pak se podíváme, jak může program zpracovávat různé signály, zatímco program provádí. Pojďme tedy začít.

Signál

Signál je událost, která je generována, aby upozornila proces nebo vlákno, že přišla nějaká důležitá situace. Když proces nebo vlákno přijme signál, proces nebo vlákno zastaví, co dělá, a provede nějakou akci. Signál může být užitečný pro komunikaci mezi procesy.

Standardní signály

Signály jsou definovány v hlavičkovém souboru signál.h jako makro konstanta. Název signálu začínal písmenem „SIG“ a následoval krátký popis signálu. Každý signál má tedy jedinečnou číselnou hodnotu. Váš program by měl vždy používat název signálů, nikoli číslo signálů. Důvodem je to, že se počet signálů může lišit podle systému, ale význam jmen bude standardní.

Makro NSIG je celkový počet definovaných signálů. Hodnota NSIG je o jeden větší než celkový počet definovaných signálů (všechna čísla signálů jsou přiřazována postupně).

Následuje standardní signál:

Název signálu Popis
ZOBRAZENÍ Zavěste proces. Signál SIGHUP se používá k hlášení odpojení terminálu uživatele, pravděpodobně proto, že došlo ke ztrátě nebo zavěšení vzdáleného připojení.
SIGINT Přerušte proces. Když uživatel zadá znak INTR (obvykle Ctrl + C), odešle se signál SIGINT.
SIGQUIT Ukončete proces. Když uživatel zadá znak QUIT (obvykle Ctrl + \), odešle se signál SIGQUIT.
SIGILL Protiprávní pokyny. Při pokusu o provedení smetí nebo privilegované instrukce je vygenerován signál SIGILL. SIGILL lze také generovat při přetečení zásobníku nebo při potížích systému se zpracováním signálu.
SIGTRAP Stopová past. Instrukce zarážky a další instrukce trapu vygenerují signál SIGTRAP. Debugger používá tento signál.
SIGABRT Přerušit. Signál SIGABRT je generován při volání funkce abort (). Tento signál označuje chybu, která je detekována samotným programem a hlášena voláním funkce abort ().
SIGFPE Výjimka s plovoucí desetinnou čárkou. Když došlo k fatální aritmetické chybě, vygeneruje se signál SIGFPE.
SIGUSR1 a SIGUSR2 Signály SIGUSR1 a SIGUSR2 lze použít, jak si přejete. Je užitečné pro ně napsat obsluhu signálu do programu, který přijímá signál pro jednoduchou meziprocesovou komunikaci.

Výchozí akce signálů

Každý signál má výchozí akci, jednu z následujících:

Období: Proces bude ukončen.
Jádro: Proces se ukončí a vytvoří soubor s výpisem jádra.
Ign: Proces bude signál ignorovat.
Stop: Proces se zastaví.
Pokračování: Proces bude pokračovat od zastavení.

Výchozí akci lze změnit pomocí funkce obslužné rutiny. Výchozí akci některých signálů nelze změnit. SIGKILL a SIGABRT Výchozí akci signálu nelze změnit ani ignorovat.

Zpracování signálu

Pokud proces přijímá signál, má pro tento druh signálu možnost volby akce. Proces může ignorovat signál, může určit funkci obslužné rutiny nebo přijmout výchozí akci pro tento druh signálu.

Můžeme zpracovat signál pomocí signál nebo sigaction funkce. Zde vidíme, jak nejjednodušší signál() funkce se používá pro zpracování signálů.

int signal () (int signum, void (* func) (int))

The signál() zavolá func funkce, pokud proces přijímá signál signum. The signál() vrací ukazatel na funkci func pokud je úspěšný, nebo vrátí chybu errno a -1 jinak.

The func ukazatel může mít tři hodnoty:

  1. SIG_DFL: Je to ukazatel na výchozí funkci systému SIG_DFL (), deklarováno v h hlavičkový soubor. Slouží k provedení výchozí akce signálu.
  2. SIG_IGN: Je to ukazatel na funkci ignorování systému SIG_IGN (),deklarováno v h hlavičkový soubor.
  3. Uživatelem definovaný ukazatel funkce obslužné rutiny: Uživatelem definovaný typ funkce obslužné rutiny je void (*) (int), znamená návratový typ je neplatný a jeden argument typu int.

Základní příklad obsluhy signálu

#zahrnout
#zahrnout
#zahrnout
void sig_handler (int signum)
// Návratový typ funkce obslužné rutiny by měl být neplatný
printf ("\ nInterní obslužná funkce \ n");

int main ()
signál (SIGINT, sig_handler); // Zaregistrujte obsluhu signálu
for (int i = 1 ;; i ++) // Nekonečná smyčka
printf ("% d: Uvnitř hlavní funkce \ n", i);
spánek (1); // Zpoždění o 1 sekundu

návrat 0;

Na snímku obrazovky výstupu příkladu 1.c, můžeme vidět, že v hlavní funkci probíhá nekonečná smyčka. Když uživatel zadal Ctrl + C, vyvolá se zastavení provádění hlavní funkce a funkce obsluhy signálu. Po dokončení funkce obslužné rutiny se pokračovalo v provádění hlavní funkce. Když uživatel zadal Ctrl + \, proces je ukončen.

Příklad ignorování signálů

#zahrnout
#zahrnout
#zahrnout
int main ()
signál (SIGINT, SIG_IGN); // Zaregistrujte obsluhu signálu pro ignorování signálu
for (int i = 1 ;; i ++) // Nekonečná smyčka
printf ("% d: Uvnitř hlavní funkce \ n", i);
spánek (1); // Zpoždění o 1 sekundu

návrat 0;

Zde je obslužná funkce zaregistrována SIG_IGN () funkce pro ignorování akce signálu. Když tedy uživatel zadal Ctrl + C,  SIGINT signál se generuje, ale akce je ignorována.

Příklad obsluhy signálu registrace

#zahrnout
#zahrnout
#zahrnout
void sig_handler (int signum)
printf ("\ nInterní obslužná funkce \ n");
signál (SIGINT, SIG_DFL); // Znovu zaregistrujte obslužný program signálu pro výchozí akci

int main ()
signál (SIGINT, sig_handler); // Zaregistrujte obsluhu signálu
for (int i = 1 ;; i ++) // Nekonečná smyčka
printf ("% d: Uvnitř hlavní funkce \ n", i);
spánek (1); // Zpoždění o 1 sekundu

návrat 0;

Na snímku obrazovky výstupu příkladu 3.c, můžeme vidět, že když uživatel poprvé zadal Ctrl + C, byla vyvolána funkce obslužné rutiny. Ve funkci obslužné rutiny se obslužná rutina signálu znovu zaregistruje SIG_DFL pro výchozí akci signálu. Když uživatel zadal Ctrl + C podruhé, proces je ukončen, což je výchozí akce SIGINT signál.

Odesílání signálů:

Proces také může explicitně posílat signály sám sobě nebo jinému procesu. pro odesílání signálů lze použít funkci raise () a kill (). Obě funkce jsou deklarovány v signálu.h soubor záhlaví.

int raise (int signum)

Funkce raise () použitá k odesílání signálu signum k procesu volání (sám). Vrací nulu, pokud je úspěšná, a nenulovou hodnotu, pokud selže.

int kill (pid_t pid, int signum)

Funkce zabití použitá k odeslání signálu signum na proces nebo skupinu procesů specifikovanou pid.

Příklad obsluhy signálu SIGUSR1

#zahrnout
#zahrnout
void sig_handler (int signum)
printf ("Funkce Inside Handler \ n");

int main ()
signál (SIGUSR1, sig_handler); // Zaregistrujte obsluhu signálu
printf ("Uvnitř hlavní funkce \ n");
zvýšit (SIGUSR1);
printf ("Uvnitř hlavní funkce \ n");
návrat 0;

Zde proces posílá signál SIGUSR1 sám sobě pomocí funkce raise ().

Raise with Kill Příklad programu

#zahrnout
#zahrnout
#zahrnout
void sig_handler (int signum)
printf ("Funkce Inside Handler \ n");

int main ()
pid_t pid;
signál (SIGUSR1, sig_handler); // Zaregistrujte obsluhu signálu
printf ("Uvnitř hlavní funkce \ n");
pid = getpid (); // Zpracovat ID sebe sama
kill (pid, SIGUSR1); // Pošlete SIGUSR1 sám sobě
printf ("Uvnitř hlavní funkce \ n");
návrat 0;

Tady je proces odeslán SIGUSR1 signál k sobě pomocí zabít() funkce. getpid () se používá k získání samotného ID procesu.

V dalším příkladu uvidíme, jak rodiče a podřízené procesy komunikují (Inter Process Communication) pomocí zabít() a signální funkce.

Komunikace rodičů a dětí se signály

#zahrnout
#zahrnout
#zahrnout
#zahrnout
void sig_handler_parent (int signum)
printf ("Rodič: Přijal signál odpovědi od dítěte \ n");

void sig_handler_child (int signum)
printf ("Dítě: Přijal signál od rodiče \ n");
spánek (1);
kill (getppid (), SIGUSR1);

int main ()
pid_t pid;
if ((pid = vidlice ())<0)
printf ("Vidlice se nezdařila \ n");
výstup (1);

/ * Podřízený proces * /
else if (pid == 0)
signál (SIGUSR1, sig_handler_child); // Zaregistrujte obsluhu signálu
printf ("Dítě: čeká na signál \ n");
pauza();

/ * Nadřazený proces * /
jiný
signál (SIGUSR1, sig_handler_parent); // Zaregistrujte obsluhu signálu
spánek (1);
printf ("Rodič: odesílání signálu dítěti \ n");
kill (pid, SIGUSR1);
printf ("Rodič: čeká na odpověď \ n");
pauza();

návrat 0;

Tady, Vidlička() funkce vytvoří podřízený proces a vrátí nulu podřízenému procesu a ID podřízeného procesu nadřazenému procesu. Bylo tedy zkontrolováno, že pid rozhoduje o procesu rodič a dítě. V nadřazeném procesu je spán po dobu 1 sekundy, aby podřízený proces mohl zaregistrovat funkci obsluhy signálu a čekat na signál od rodiče. Po 1 s nadřazený proces odeslat SIGUSR1 signál dítěti zpracovat a čekat na signál odezvy od dítěte. V podřízeném procesu nejprve čeká na signál od rodiče a při přijetí signálu je vyvolána funkce obsluhy. Z funkce obslužné rutiny podřízený proces odešle další SIGUSR1 signál rodiči. Tady getppid () funkce se používá pro získání ID nadřazeného procesu.

Závěr

Signál v Linuxu je velké téma. V tomto článku jsme viděli, jak zacházet se signálem od samého základu, a také získat znalosti o tom, jak se signál generuje, jak může proces posílat signál sám sobě a dalšímu procesu, jak lze signál použít pro meziprocesovou komunikaci.

Kurzor při psaní v systému Windows 10 skáče nebo se pohybuje náhodně
Pokud zjistíte, že kurzor myši skáče nebo se pohybuje sám, automaticky, náhodně při psaní v notebooku nebo počítači se systémem Windows, pak vám někte...
Jak obrátit směr posouvání myši a touchpadu ve Windows 10
Myš a Touchpadnejenže usnadňují výpočet, ale jsou efektivnější a méně časově náročné. Nemůžeme si představit život bez těchto zařízení, ale přesto je ...
Jak změnit velikost, barvu a schéma kurzoru myši a kurzoru v systému Windows 10
Ukazatel myši a kurzor ve Windows 10 jsou velmi důležité aspekty operačního systému. To lze říci i pro jiné operační systémy, takže ve skutečnosti nej...