C Programiranje

Kako uporabljati obdelovalce signalov v jeziku C?

Kako uporabljati obdelovalce signalov v jeziku C?
V tem članku vam bomo pokazali, kako uporabljati obdelovalce signalov v Linuxu z uporabo jezika C. Najprej pa bomo razpravljali o tem, kaj je signal, kako bo ustvaril nekaj običajnih signalov, ki jih lahko uporabite v svojem programu, nato pa bomo preučili, kako lahko program obdeluje različne signale med izvajanjem programa. Torej, začnimo.

Signal

Signal je dogodek, ki se ustvari, da obvesti postopek ali nit, da je prišlo do neke pomembne situacije. Ko postopek ali nit prejme signal, postopek ali nit ustavi svoje početje in nekaj ukrepa. Signal je lahko koristen za medprocesno komunikacijo.

Standardni signali

Signali so definirani v datoteki glave signal.h kot makro konstanto. Ime signala se je začelo s "SIG", čemur je sledil kratek opis signala. Torej, vsak signal ima edinstveno številčno vrednost. Vaš program mora vedno uporabljati ime signalov in ne številke signalov. Razlog je v tem, da se številka signala razlikuje glede na sistem, vendar bo pomen imen standarden.

Makro NSIG je skupno število definiranih signalov. Vrednost NSIG je za eno večje od skupnega števila definiranih signalov (vsa številka signala se dodeli zaporedno).

Sledijo standardni signali:

Ime signala Opis
VZDIH Odložite postopek. Signal SIGHUP se uporablja za poročanje o prekinitvi uporabniškega terminala, morda zato, ker se oddaljena povezava izgubi ali prekine.
POMEN Prekinite postopek. Ko uporabnik vnese znak INTR (običajno Ctrl + C), se pošlje signal SIGINT.
SIGQUIT Zaprite postopek. Ko uporabnik vnese znak QUIT (običajno Ctrl + \), se pošlje signal SIGQUIT.
PREPRIČAJ Nezakonita navodila. Ko poskusite izvesti smeti ali privilegirana navodila, se ustvari signal SIGILL. Prav tako lahko SIGILL ustvarite, ko se sklad prelije ali ko ima sistem težave z zagonom upravljalnika signalov.
SIGTRAP Pasti v sledovih. Navodilo točke zaustavitve in druga navodila za lovljenje bodo ustvarili signal SIGTRAP. Razhroščevalec uporablja ta signal.
SIGABRT Prekini. Signal SIGABRT se ustvari, ko je poklicana funkcija abort (). Ta signal označuje napako, ki jo zazna sam program in jo sporoči klic funkcije abort ().
SIGFPE Izjema s plavajočo vejico. Ko pride do usodne aritmetične napake, se ustvari signal SIGFPE.
SIGUSR1 in SIGUSR2 Signala SIGUSR1 in SIGUSR2 lahko uporabljate, kot želite. V program, ki sprejema signal za preprosto medprocesno komunikacijo, jim je koristno napisati obdelovalec signala.

Privzeto dejanje signalov

Vsak signal ima privzeto dejanje, eno od naslednjega:

Izraz: Postopek se bo končal.
Jedro: Postopek se bo končal in ustvaril osnovno datoteko izpisa.
Vžig: Postopek bo signal prezrl.
Stop: Postopek se bo ustavil.
Nadaljevanje: Postopek se ne bo ustavil.

Privzeto dejanje je mogoče spremeniti s funkcijo vodnika. Privzetega dejanja nekaterih signalov ni mogoče spremeniti. SIGKILL in SIGABRT privzetega dejanja signala ni mogoče spremeniti ali prezreti.

Ravnanje s signali

Če postopek prejme signal, ima postopek možnost izbire ukrepov za to vrsto signala. Proces lahko prezre signal, lahko poda funkcijo upravljavca ali sprejme privzeto dejanje za to vrsto signala.

Signal lahko obvladamo z uporabo signal ali prenašanje funkcijo. Tu vidimo, kako najbolj preprosto signal () funkcija se uporablja za obdelavo signalov.

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

The signal () bo poklical func funkcijo, če postopek prejme signal signum. The signal () vrne kazalec v funkcijo func če je uspešen ali vrne napako na errno in -1 drugače.

The func kazalec ima lahko tri vrednosti:

  1. SIG_DFL: Je kazalec na privzeto funkcijo sistema SIG_DFL (), razglašena v h datoteka glave. Uporablja se za privzeto dejanje signala.
  2. SIG_IGN: Je kazalec na funkcijo prezrtja sistema SIG_IGN (),razglašen v h datoteka glave.
  3. Kazalec funkcije, ki ga določi uporabnik: Uporabniško določena vrsta funkcije vodnika je void (*) (int), pomeni, da je vrsta vrnitve nična in en argument vrste int.

Primer osnovnega upravljavca signalov

#include
#include
#include
void sig_handler (int signum)
// Vrnjeni tip funkcije obdelovalca mora biti ničen
printf ("\ nInside handler function \ n");

int main ()
signal (SIGINT, sig_handler); // Registriraj obdelavo signalov
for (int i = 1 ;; i ++) // Neskončna zanka
printf ("% d: Znotraj glavne funkcije \ n", i);
spanje (1); // Zamuda za 1 sekundo

vrnitev 0;

Na posnetku zaslona rezultata Primer1.c, lahko vidimo, da se v glavni funkciji izvaja neskončna zanka. Ko uporabnik vtipka Ctrl + C, se glavno izvajanje funkcije ustavi in ​​prikliče se funkcija obdelave signala. Po zaključku funkcije vodnika se je izvajanje glavne funkcije nadaljevalo. Ko je uporabniški tip vtipkal Ctrl + \, je postopek končan.

Primer prezre signalov

#include
#include
#include
int main ()
signal (SIGINT, SIG_IGN); // Registriraj obdelovalec signala za ignoriranje signala
for (int i = 1 ;; i ++) // Neskončna zanka
printf ("% d: Znotraj glavne funkcije \ n", i);
spanje (1); // Zamuda za 1 sekundo

vrnitev 0;

Tu je funkcija obdelovalca registrirana za SIG_IGN () funkcija za prezrtje signalnega delovanja. Torej, ko je uporabnik vpisal Ctrl + C,  POMEN signal ustvarja, vendar se dejanje prezre.

Primer ponovne registracije upravljavca signalov

#include
#include
#include
void sig_handler (int signum)
printf ("\ nInside handler function \ n");
signal (SIGINT, SIG_DFL); // Ponovno registriraj obdelovalca signalov za privzeto dejanje

int main ()
signal (SIGINT, sig_handler); // Registriraj obdelavo signalov
for (int i = 1 ;; i ++) // Neskončna zanka
printf ("% d: Znotraj glavne funkcije \ n", i);
spanje (1); // Zamuda za 1 sekundo

vrnitev 0;

Na posnetku zaslona rezultata Primer3.c, lahko vidimo, da je uporabnik, ko je uporabnik prvič vpisal Ctrl + C, poklical funkcijo vodnika. V funkciji handler se upravljalec signala ponovno registrira na SIG_DFL za privzeto delovanje signala. Ko uporabnik drugič vnese Ctrl + C, se postopek zaključi, kar je privzeto dejanje POMEN signal.

Pošiljanje signalov:

Postopek lahko tudi izrecno pošilja signale sebi ali drugemu procesu. funkcijo rise () in kill () lahko uporabite za pošiljanje signalov. Obe funkciji sta prijavljeni v signalu.h datoteka z glavo.

int dvig (int signum)

Funkcija dviga (), ki se uporablja za pošiljanje signala signum klicnemu procesu (samemu sebi). Vrne nič, če je uspešna, in drugačna vrednost, če ne uspe.

int kill (pid_t pid, int signum)

Funkcija ubijanja, ki se uporablja za pošiljanje signala signum v postopek ali skupino procesov, ki jo določa pid.

Primer obdelave signala SIGUSR1

#include
#include
void sig_handler (int signum)
printf ("Funkcija notranjega vodnika \ n");

int main ()
signal (SIGUSR1, sig_handler); // Registriraj obdelavo signalov
printf ("Notranjost glavne funkcije \ n");
dvig (SIGUSR1);
printf ("Notranjost glavne funkcije \ n");
vrnitev 0;

Tu postopek sam pošlje signal SIGUSR1 s pomočjo funkcije rise ().

Dvignite s programom Primer ubijanja

#include
#include
#include
void sig_handler (int signum)
printf ("Funkcija notranjega vodnika \ n");

int main ()
pid_t pid;
signal (SIGUSR1, sig_handler); // Registriraj obdelavo signalov
printf ("Notranjost glavne funkcije \ n");
pid = getpid (); // ID samega procesa
ubiti (pid, SIGUSR1); // SIGUSR1 pošljite sebi
printf ("Notranjost glavne funkcije \ n");
vrnitev 0;

Tukaj postopek pošljite SIGUSR1 signal samemu sebi z uporabo kill () funkcijo. getpid () se uporablja za pridobivanje ID-ja samega procesa.

V naslednjem primeru bomo videli, kako komunicirajo nadrejeni in podrejeni procesi (Inter Process Communication) z uporabo kill () in signalna funkcija.

Komunikacija staršev z signali

#include
#include
#include
#include
void sig_handler_parent (int signum)
printf ("Starš: od otroka je prejel odzivni signal \ n");

void sig_handler_child (int signum)
printf ("Child: Prejel signal od starša \ n");
spanje (1);
kill (getppid (), SIGUSR1);

int main ()
pid_t pid;
če ((pid = fork ())<0)
printf ("Fork Failed \ n");
izhod (1);

/ * Otroški postopek * /
sicer če (pid == 0)
signal (SIGUSR1, sig_handler_child); // Registriraj obdelavo signalov
printf ("Otrok: čakanje na signal \ n");
pavza();

/ * Nadrejeni postopek * /
sicer
signal (SIGUSR1, sig_handler_parent); // Registriraj obdelavo signalov
spanje (1);
printf ("Starš: pošiljanje signala otroku \ n");
ubiti (pid, SIGUSR1);
printf ("Starš: čakanje na odgovor \ n");
pavza();

vrnitev 0;

Tukaj, vilice () funkcija ustvari podrejeni proces in vrne ničlo podrejenemu procesu in podrejeni ID procesa nadrejenemu procesu. Torej, pid je bil preverjen, da se odloči za starše in otroke. V nadrejenem procesu je v stanju mirovanja 1 sekundo, tako da lahko podrejeni postopek registrira funkcijo obdelave signala in počaka na signal od starša. Po 1 sekundi nadrejenega postopka pošljite SIGUSR1 signal otroku in počakajte na odzivni signal otroka. V podrejenem procesu najprej čaka na signal od starša, in ko je signal sprejet, se prikliče funkcija vodnika. Iz funkcije obdelovalca podrejeni proces pošlje drugega SIGUSR1 signal staršu. Tukaj getppid () funkcija se uporablja za pridobivanje ID-ja nadrejenega procesa.

Zaključek

Signal v Linuxu je velika tema. V tem članku smo videli, kako ravnati s signalom iz samega osnovnega, in dobili tudi znanje o tem, kako signal ustvarja, kako lahko proces pošlje signal sebi in drugim procesom, kako se signal lahko uporablja za medprocesno komunikacijo.

WinMouse vam omogoča prilagajanje in izboljšanje premikanja kazalca miške v računalniku z operacijskim sistemom Windows
Če želite izboljšati privzete funkcije kazalca miške, uporabite brezplačno programsko opremo WinMouse. Dodaja več funkcij, s pomočjo katerih boste kar...
Levi gumb miške ne deluje v sistemu Windows 10
Če s prenosnikom ali namiznim računalnikom uporabljate namensko miško, vendar gumb miške z levim klikom ne deluje v operacijskem sistemu Windows 10/8/...
Kazalec skoči ali se naključno premika med tipkanjem v sistemu Windows 10
Če ugotovite, da kazalec miške med tipkanjem v prenosnem računalniku ali računalniku Windows samodejno, naključno preskakuje ali se premika sam, vam l...