Оқулық «Федералдық білім беруді дамыту институты»



Pdf көрінісі
бет122/158
Дата01.07.2023
өлшемі3.83 Mb.
#475485
түріОқулық
1   ...   118   119   120   121   122   123   124   125   ...   158
операциялық жуйелер

10.3.5. СИГНАЛДАРДЫ ӨҢДЕУШІМЕН 
БАСҚАРУ 
 
Процеспен сигналды алған соң бұл сигналға сәйкес келетін- сигнал-
өңдеуші кестесінің жолы өшіріледі. Егер процеспен сигналды 
қабылдаған соң, сигнал өңдеушісі қайта құрылмаса, онда сигналды 
аларда әдеттегідей өңдеуші шақырылады. Сигналды өңдеушіні қайта 
құру үшін әдетте сигналдың өңдеуші-функциясы денесіне signal() 
шақыру функциясын сыйғызады. Мысалы, келесі бағдарлама әр 
SIGINT сигналын алуы кезінде, сонымен қатар сигналды қабылдау 
үнемі күтетін «Сигнал қабылданды» жолын шығарады: 
#include 
#include  
void handler(int sig_no)
{
signal(sig_no, &handler); 
printf("Signal caught\n");

int main()
{
signal( SIGINT, &handler); 
while(1)
{
printf("Waiting for signal...\n"); 
pause();
}
return 0;



194 
Бұл 
бағдарламаны 
іске 
қосарда 
(ағымдағы 
каталогтағы 
орындалатын файл — signal3) келесі міндеттер: 
#!/bin/bash
./signal3 &
pid=$!
sleep 1
kill -SIGINT $pid
sleep 1
kill -SIGINT $pid
sleep 1
kill -SIGTERM $pid 
экранға шығарылады: 
Waiting for signal...
Signal caught
Waiting for signal...
Signal caught
Waiting for signal...
./signal3.sh: line 10: 1044 Terminated 
Берілген бағдарлама SIGINT сигнал өңдеушісін — handler() 
функциясын орнатады, одан кейін шексіз циклге кіреді, ол өзінің 
орындалуын сигналды қабылдағанға дейін тоқтатады, бұл сәйкес 
келетін хабарламаны шығарады. Сигналды қабылдаумен қатар басқару 
handler() функциясына беріледі, ол пайдаланушыны сигналдың түсуін 
хабарлайтын хабарламаны шығарады және сигналдың өңделуін 
қалпына келтіреді. Осыдан кейін басқару pause() кейінгі командаға 
беріледі, яғни шексіз циклдің келесі итерациясы басталады. 
Өңдеуші кестені, келесі сигналдың осы өңдеушімен өңделетіндей 
етіп қалпына келтіруі міндетті емес. Өңдеушілердің қалпына келуін 
процесстің сигналға реакциясы ағымдағы уақытпен алмасуы міндетті 
болатын жағдайларда пайдалануға болады. 
Мысалы, келесі SIGINT сигналының тақ санын алуы кезінде
бағдарлама A әрпін шақырады (бірінші, үшінші және т.б.) және SIGINT 
сигналының жұп санын алу кезінде B әрпін шақырады (екінші, 
төртінші және т.б.). Бұл әсерге, SIGINT өңдеуші сигналдың сатылы 


195 
ауысымымен ғана жетуге болады: 
#include 
#include  
void handler1(int sig_no); 
void handler2(int sig_no); 
void handler1(int sig_no)
{
signal(sig_no, &handler2); 
printf("A\n");

void handler2(int sig_no)
{
signal(sig_no, &handler1); 
printf("B\n");
}
int main()
{
signal(SIGINT, &handler1); 
while (1)
pause();
return 0;

Келесі 
тапсырмада 
осы 
бағдарламаны 
орындау 
кезінде 
(бағдарламаның орындалатын файлдың атауы — signal4 деп 
тұжырымдалады): 
#!/bin/bash
./a &
pid=$!
sleep 1
kill -SIGINT $pid 
sleep 1
kill -SIGINT $pid 
sleep 1
kill -SIGINT $pid 
sleep 1
kill -SIGINT $pid 
sleep 1


196 
kill -SIGTERM $pid
экранға шығарылады: 
A
B
A
B
./signal4.sh: line 14: 2452 Terminated
Жоғарыда қарастырылған сигналдар механизмінің уақытша 
шектеулері — пайдаланушы өңделуінің орнатылуына дейін сигналды 
қабылдау кезінде әдеттегідей өңдеушіні шақыру – тек бағдарламаның 
негізгі функцияларын орындау уақытында ғана емес, өңдеуші-
функцияның орындалу уақытында да әрекет етеді. 
Осылайша, егер өңделушінің бірінші командасымен сигнал 
өңделуін қалпына келтірсе (алдыңғы үлгілерде жасалғандай) 
өңдеушінің кез келген келесі команданы орындау сәтінде сигналды алу 
кезінде өңдеушінің өңделушінің орындалуы тоқтатылуына болады. 
Сигналды қабылдау сәтінде өңделуші қалпына келген болса, онда ол 
қайта жаңадан іске қосылады. Егер оның орындалу уақытында жаңа 
сигнал қабылданбаса, басқару сол өңдеуші-функциясына қайта келеді. 
Мұндай тәртіп функцияның рекурсивтік шақыртуларымен ұқсас 
келеді, сонымен қатар мұндай «рекурсияның» тереңдігі, өңдеушілердің 
орындалу уақытында алынған сигналдардың санына тең болады. 
Әдебиетте әдетте, «өңдеушінің рекурсивтік шақырылуы» деген термин 
кездеседі. Мұндай атау тіпті дұрыс емес, себебі қарапайым 
рекурсиямен ешқандай ортақтығы жоқ. 
Өңдеушінің соңғы жолына signal() шақырту функциясын сыйғыза 
отырып, өңдеушінің қалпына келтірсе, процестің күйі басқаша болады. 
Осылайша өңдеуші шақыртуларының қайталауынан құтылуға болады, 
бірақ процес оның өңделушімен қалпына келу сәтіне дейін, сигнал 
қабылдап алса, процестің орындалуын аяқтайтын әдеттегідей өңдеуші 
шақырылады. 
Жоғарыда көрсетілген қиындықтардан құтылу үшін үш нұсқаның 
біреуін пайдалануға болады:
1) Көлемді және сигнал өңдеушінің бағдарламалық кодының 
қиындығын азайту, осылайша оның орындалу уақытын азайтамыз, 
демек, өңдеушінің орындалуы кезінде сигнал қабылдау мүмкіндігі;
2) Өңдеуші тәсілдері туралы қабылданған шешімдерді кейінге 
қалдыру және SIG IGN сигналдарын елемейтін тұрақты шамалардың 
көмегімен елемеу. 


197 
SIG_IGN тұрақты шамалары өңдеуші функцияның мекенжайы 
орнына, signal() функциясының параметрі ретінде ұсынылады.
Сигналды елемеуді орнатқаннан кейін олар үшін ешқандай өңдеуші — 
әдеттегідей пайдаланушы да, өңдеуші де шақырылмайды. Осылайша, 
өзі қайталанатын шақырулардан және әдеттегідей өңдеушінің 
шақыруынан қорғай отырып, өңдеуші-функцияның басында сигналды 
елемеу режимін орнатуға болады, ал өңдеушіні функцияның аяғында 
қалпына келтіруге болады. 
Типтік өңдеуші бұл жағдайда мынадай болады:
void handler(int sig_no)
{
signal( sig_no, SIG_IGN); 
... 
... 
signal( sig_no, &handler);
}
3) Сигналды пердені пайдалану. 


Достарыңызбен бөлісу:
1   ...   118   119   120   121   122   123   124   125   ...   158




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет