Paano gamitin ang mga handler ng signal sa wika ng C?

How Use Signal Handlers C Language



Sa artikulong ito ay ipapakita namin sa iyo kung paano gamitin ang mga handler ng signal sa Linux gamit ang C na wika. Ngunit tatalakayin muna namin kung ano ang signal, kung paano ito makakabuo ng ilang mga karaniwang signal na maaari mong gamitin sa iyong programa at pagkatapos ay titingnan namin kung paano mapangasiwaan ang isang iba't ibang mga signal ng isang programa habang nagpapatupad ng programa. Kaya, magsimula na tayo.

Hudyat

Ang isang senyas ay isang kaganapan na nabuo upang ipaalam sa isang proseso o thread na dumating ang ilang mahahalagang sitwasyon. Kapag ang isang proseso o thread ay nakatanggap ng isang senyas, ang proseso o thread ay titigil sa ginagawa nito at magsasagawa ng pagkilos. Ang signal ay maaaring maging kapaki-pakinabang para sa inter-proseso na komunikasyon.







Mga Karaniwang Signal

Ang mga signal ay tinukoy sa header file signal.h bilang isang pare-pareho ang macro. Ang pangalan ng signal ay nagsimula sa isang SIG at sinundan ng isang maikling paglalarawan ng signal. Kaya, ang bawat signal ay may natatanging halaga sa bilang. Dapat palaging gamitin ng iyong programa ang pangalan ng mga signal, hindi ang numero ng signal. Ang dahilan ay ang numero ng signal ay maaaring magkakaiba ayon sa system ngunit ang kahulugan ng mga pangalan ay magiging pamantayan.



Ang macro NSIG ay ang kabuuang bilang ng signal na tinukoy. Ang halaga ng NSIG ay isang mas malaki kaysa sa kabuuang bilang ng signal na tinukoy (Ang lahat ng mga signal number ay inilalaan nang sunud-sunod).



Ang sumusunod ay ang karaniwang mga signal:





Pangalan ng Signal Paglalarawan
SIGHUP I-hang-up ang proseso. Ginagamit ang signal ng SIGHUP upang iulat ang pagkakakonekta ng terminal ng gumagamit, posibleng dahil nawala ang isang remote na koneksyon o mag-hang up.
SIGINT Gambala ang proseso. Kapag na-type ng gumagamit ang INTR character (karaniwang Ctrl + C) ipinapadala ang SIGINT signal.
SIGQUIT Itigil ang proseso. Kapag nag-type ang gumagamit ng QUIT character (karaniwang Ctrl + ) ang SIGQUIT signal ay ipinadala.
Selyo Ilegal na tagubilin. Kapag may pagtatangka upang magpatupad ng basura o may pribilehiyong tagubilin, mabubuo ang signal ng SIGILL. Gayundin, maaaring mabuo ang SIGILL kapag umapaw ang stack, o kapag nagkakaproblema ang system sa pagpapatakbo ng isang handler ng signal.
SIGTRAP Bakas ang bitag. Ang isang tagubilin sa breakpoint at iba pang tagubilin sa bitag ay bubuo ng signal ng SIGTRAP. Gumagamit ang debugger ng senyas na ito.
SIGABRT Pagpapalaglag Ang signal ng SIGABRT ay nabuo kapag tinawag ang pagpapa-abort () na function. Ang senyas na ito ay nagpapahiwatig ng isang error na napansin ng programa mismo at iniulat ng abort () na tawag sa pagpapaandar.
SIGFPE Pagbubukod sa puntos na lumulutang. Kapag naganap ang isang nakamamatay na error sa arithmetic ang signal ng SIGFPE ay nabuo.
SIGUSR1 at SIGUSR2 Ang mga signal SIGUSR1 at SIGUSR2 ay maaaring magamit ayon sa gusto mo. Kapaki-pakinabang na magsulat ng isang handler ng signal para sa kanila sa programa na tumatanggap ng signal para sa simpleng komunikasyon na inter-proseso.

Default na Pagkilos Ng Mga Signal

Ang bawat signal ay may isang default na aksyon, isa sa mga sumusunod:

Kataga: Tatapusin ang proseso.
Core: Tatapusin ang proseso at gagawa ng isang pangunahing dump file.
Ign: Hindi papansinin ng proseso ang signal.
Itigil: Titigil ang proseso.
Account: Ang proseso ay magpapatuloy mula sa pagtigil.



Maaaring mabago ang default na pagkilos gamit ang pagpapaandar ng handler. Hindi mababago ang default na pagkilos ng ilang signal. SIGKILL at SIGABRT ang default na pagkilos ng signal ay hindi maaaring mabago o balewalain.

Paghawak ng Signal

Kung ang isang proseso ay tumatanggap ng isang senyas, ang proseso ay may pagpipilian ng aksyon para sa ganoong uri ng signal. Maaaring balewalain ng proseso ang signal, maaaring tukuyin ang isang handler function, o tanggapin ang default na aksyon para sa ganoong uri ng signal.

  • Kung ang tinukoy na pagkilos para sa signal ay hindi pinansin, pagkatapos ang signal ay itinapon kaagad.
  • Ang programa ay maaaring magparehistro ng isang function ng handler gamit ang pagpapaandar tulad ng signal o panggugulo . Tinatawag itong handler na nakakakuha ng signal.
  • Kung ang signal ay hindi napangasiwaan o hindi pinansin, magaganap ang default na pagkilos nito.

Maaari naming hawakan ang signal gamit ang signal o panggugulo pagpapaandar Narito nakikita natin kung paano ang pinakasimpleng signal () ang pagpapaandar ay ginagamit para sa paghawak ng mga signal.

intsignal() (inttanda, walang bisa (*pagpapaandar)(int))

Ang signal () tatawag sa pagpapaandar pag-andar kung ang proseso ay tumatanggap ng isang senyas tanda . Ang signal () nagbabalik ng isang pointer upang gumana pagpapaandar kung matagumpay o nagbabalik ng isang error sa errno at -1 kung hindi man.

Ang pagpapaandar ang pointer ay maaaring magkaroon ng tatlong mga halaga:

  1. SIG_DFL : Ito ay isang pointer sa pagpapaandar ng system default SIG_DFL () , idineklara sa h file ng header. Ginagamit ito para sa pagkuha ng default na pagkilos ng signal.
  2. SIG_IGN : Ito ay isang pointer upang hindi pansinin ng system ang pagpapaandar SIG_IGN () , idineklara sa h file ng header.
  3. Tinukoy ng gumagamit ang handler function pointer : Ang tinukoy ng gumagamit na uri ng pagpapaandar ng handler ay walang bisa (*) (int) , nangangahulugang ang uri ng pagbalik ay walang bisa at isang pagtatalo ng uri ng int.

Pangunahing Halimbawa ng Handler ng Signal

# isama
# isama
# isama
walang bisasig_handler(inttanda){

// Return type ng handler function ay dapat na walang bisa
printf (' nPag-andar sa loob ng handler n');
}

intpangunahing(){
signal(SIGINT,sig_handler); // Magrehistro handler ng signal
para sa(intako=1;;ako++){ // Walang katapusang loop
printf ('% d: Sa loob ng pangunahing pagpapaandar n',ako);
matulog(1); // Delay ng 1 segundo
}
bumalik ka 0;
}

Sa screenshot ng output ng Halimbawa1.c, maaari naming makita na sa pangunahing pagpapaandar na walang katapusan na loop ay isinasagawa. Kapag nag-type ang gumagamit ng Ctrl + C, ang pangunahing pagpapaandar ng pagpapatupad ng pagpapaandar at ang pagpapaandar ng handler ng signal ay tinawag. Matapos makumpleto ang pagpapaandar ng handler, ipinagpatuloy ang pangunahing pagpapatupad ng pagpapaandar. Kapag nag-type ang gumagamit ng Ctrl + , ang proseso ay umalis.

Huwag pansinin ang Halimbawa ng Mga Hudyat

# isama
# isama
# isama
intpangunahing(){
signal(SIGINT,SIG_IGN); // Magrehistro ng handler ng signal para sa pagwawalang bahala ng signal

para sa(intako=1;;ako++){ // Walang katapusang loop
printf ('% d: Sa loob ng pangunahing pagpapaandar n',ako);
matulog(1); // Delay ng 1 segundo
}
bumalik ka 0;
}

Narito ang pag-andar ng handler ay nakarehistro SIG_IGN () pagpapaandar para sa hindi pagpapansin sa pagkilos ng signal. Kaya, nang nag-type ang gumagamit ng Ctrl + C, SIGINT bumubuo ang signal ngunit hindi pinansin ang aksyon.

Halimbawa ng Reregister Signal Handler Halimbawa

# isama
# isama
# isama

walang bisasig_handler(inttanda){
printf (' nPag-andar sa loob ng handler n');
signal(SIGINT,SIG_DFL); // Re Magrehistro ng signal handler para sa default na pagkilos
}

intpangunahing(){
signal(SIGINT,sig_handler); // Magrehistro handler ng signal
para sa(intako=1;;ako++){ // Walang katapusang loop
printf ('% d: Sa loob ng pangunahing pagpapaandar n',ako);
matulog(1); // Delay ng 1 segundo
}
bumalik ka 0;
}

Sa screenshot ng output ng Halimbawa3.c, maaari naming makita na noong unang beses na nag-type ang gumagamit ng Ctrl + C, naimbitahan ang pagpapaandar ng handler. Sa pagpapaandar ng handler, muling nagparehistro ang signal handler SIG_DFL para sa default na pagkilos ng signal. Kapag nag-type ang gumagamit ng Ctrl + C sa pangalawang pagkakataon, natapos ang proseso na ang default na pagkilos ng SIGINT signal

Pagpapadala ng Mga Sinyales:

Ang isang proseso ay maaari ring malinaw na magpadala ng mga signal sa sarili nito o sa ibang proseso. itaas () at pumatay () function na maaaring magamit para sa pagpapadala ng mga signal. Ang parehong mga pag-andar ay idineklara sa signal.h header file.

int taasan (inttanda)

Ang pagtaas () na pagpapaandar na ginamit para sa pagpapadala ng signal tanda sa proseso ng pagtawag (mismo). Nagbabalik ito ng zero kung matagumpay at isang nonzero na halaga kung nabigo ito.

intpatayin(pid_t pid, inttanda)

Ang function na pumatay na ginamit para magpadala ng isang senyas tanda sa isang proseso o pangkat ng proseso na tinukoy ng pid .

SIGUSR1 Halimbawa ng Handler ng Signal

# isama
# isama

walang bisasig_handler(inttanda){
printf ('Sa loob ng pagpapaandar ng handler n');
}

intpangunahing(){
signal(SIGUSR1,sig_handler); // Magrehistro handler ng signal
printf ('Sa loob ng pangunahing pagpapaandar n');
taasan (SIGUSR1);
printf ('Sa loob ng pangunahing pagpapaandar n');
bumalik ka 0;
}

Dito, ang proseso ay nagpapadala ng SIGUSR1 signal sa sarili nito gamit ang pagtaas () na pagpapaandar.

Itaas gamit ang Patlang na Halimbawa ng Program

# isama
# isama
# isama
walang bisasig_handler(inttanda){
printf ('Sa loob ng pagpapaandar ng handler n');
}

intpangunahing(){
pid_t pid;
signal(SIGUSR1,sig_handler); // Magrehistro handler ng signal
printf ('Sa loob ng pangunahing pagpapaandar n');
pid=getpid(); // Iproseso mismo ang ID
patayin(pid,SIGUSR1); // Magpadala ng SIGUSR1 sa sarili nito
printf ('Sa loob ng pangunahing pagpapaandar n');
bumalik ka 0;
}

Dito, ipinapadala ang proseso SIGUSR1 signal sa sarili nito gamit patayin () pagpapaandar getpid () ay ginagamit upang makuha ang proseso ng ID ng kanyang sarili.

Sa susunod na halimbawa makikita natin kung paano pinoproseso ng magulang at anak ang pakikipag-usap (Inter Process Communication) na ginagamit patayin () at pagpapaandar ng signal.

Pakikipag-usap sa Magulang ng Bata na may Mga Sinyales

# isama
# isama
# isama
# isama
walang bisasig_handler_parent(inttanda){
printf ('Magulang: Nakatanggap ng isang senyas ng pagtugon mula sa bata n');
}

walang bisasig_handler_child(inttanda){
printf ('Anak: Nakatanggap ng isang senyas mula sa magulang n');
matulog(1);
patayin(getppid(),SIGUSR1);
}

intpangunahing(){
pid_t pid;
kung((pid=tinidor())<0){
printf (Nabigo ang Fork n');
labasan (1);
}
/ * Proseso ng Bata * /
iba pa kung(pid==0){
signal(SIGUSR1,sig_handler_child); // Magrehistro handler ng signal
printf ('Bata: naghihintay para sa signal n');
huminto();
}
/ * Proseso ng Magulang * /
iba pa{
signal(SIGUSR1,sig_handler_parent); // Magrehistro handler ng signal
matulog(1);
printf ('Magulang: nagpapadala ng signal sa Bata n');
patayin(pid,SIGUSR1);
printf ('Magulang: naghihintay para sa tugon n');
huminto();
}
bumalik ka 0;
}

Dito, tinidor () Lumilikha ang pagpapaandar ng proseso ng bata at ibabalik ang zero sa proseso ng bata at proseso ng proseso ng bata sa proseso ng magulang. Kaya, ang pid ay nasuri upang magpasya sa proseso ng magulang at anak. Sa proseso ng magulang, natutulog ito ng 1 segundo upang ang proseso ng bata ay maaaring magparehistro ng pagpapaandar ng signal handler at maghintay para sa signal mula sa magulang. Pagkatapos ng 1 segundo proseso ng magulang magpadala SIGUSR1 signal sa proseso ng bata at hintayin ang signal ng pagtugon mula sa bata. Sa proseso ng bata, una itong naghihintay para sa signal mula sa magulang at kapag natanggap ang signal, ang function ng handler ay naimbitahan. Mula sa pagpapaandar ng handler, ang proseso ng bata ay nagpapadala ng isa pa SIGUSR1 signal sa magulang. Dito getppid () Ginagamit ang pagpapaandar para sa pagkuha ng ID ng proseso ng magulang.

Konklusyon

Ang signal sa Linux ay isang malaking paksa. Sa artikulong ito nakita namin kung paano hawakan ang signal mula sa pangunahing kaalaman, at makakuha din ng isang kaalaman kung paano bumubuo ang signal, kung paano ang isang proseso ay maaaring magpadala ng signal sa sarili nito at iba pang proseso, kung paano magagamit ang signal para sa komunikasyon na inter-proseso.