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 өңдеуші сигналдың сатылы
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) Сигналды пердені пайдалану.
Достарыңызбен бөлісу: