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


      10.3.9.  ПРОЦЕССТЕРДІҢ  ҮЙЛЕСІМДІЛІГІ



Pdf көрінісі
бет180/220
Дата25.02.2022
өлшемі2,22 Mb.
#26438
түріОқулық
1   ...   176   177   178   179   180   181   182   183   ...   220
205 
 
 
10.3.9.  ПРОЦЕССТЕРДІҢ  ҮЙЛЕСІМДІЛІГІ 
Себептері  алдыңғы  тарауларда  көрсетілген  сигналдарды  жоғалту 
мәселелерін  болдырмас  үшін  процестер  аралығында  сигналдар 
алмасуын,  қабылдаушы-процестің  оны  дұрыс  өңдейтін  жағдайда 
болғанда,  таратушы-процесс  кезекті  сигналды
  ертерек  бергенге  дейін 
ұйымдастыру қажет.
 
Осындай  тәсілді  іске  асыруда  мүмкін  болатын  әдістердің  бірі  - 
жіберуші-процесс  сигналды  уақыт  аралығында  береді,  алдыңғы 
сигналдың өңделуін және өңделушінің қалпына келуін көп талап ететін 
қабылдаушы-процесс.  Мысалы,  келесі  бағдарлама  екі  процесті  іске 
асырады— оның іске асырылуы кезінде туындайтын аталық және fork() 
іске қосылумен туған еншілес. Еншілес процесс жіберуші рөліне түседі 
және  аталық  процеске    SIGINT    сигналын  1  секундта  жіберілімдер 
арасында  10  интервалмен  жібереді.  Қабылдаушы  (аталық  процесс) 
сигналды  қабылдауға  жауап  ретінде  сигнал,  олармен  қабылданған 
SIGINT  сигналдардың  жалпы  санын  шығарады.  Серияларды  жіберу 
үшін 10 сигналдан SIGINT жіберушісі SIGTERM қабылдаушысына оны 
аяқтай  отырып,  сигнал  жібереді,  одан  кейін  өзінің  орындалуын 
аяқтайды:  
 
#include 
 /*  Linux –ке қажет емес*/
 
#include 
 
#include 
 
#include 
 
int num;
 
void handler(int sig_no)
 
{
 
signal(sig_no, &handler); 
num++;
 
printf("%d\n", num);
 
}
 
int main()
 
{
 
pid_t pid; 
int i; num 
= 0;
 
setvbuf(stdout,(char*)NULL,_IONBF,0);
 
switch (pid=fork())
 
{
 


 
206 
 
case -1:
 
perror("Fork error"); 
exit(1);
 
break; case 0:
 
sleep(5); /* аталыққа қою үшін уақыт береміз */
 
/* өңдеуші */ 
for (i=0; i<10; i++)
 
{
 
kill( getppid(), SIGINT); /* Шлем SIGINT */ sleep(1); /* 
қабылдаушының дайын болғанын күтеміз */
 
}
 
kill( getppid(), SIGTERM); /* қабылдауды аяқтаймыз */
 
_exit(0); /* жіберушіні аяқтаймыз */
 
break;
 
default:
 
signal( SIGINT, &handler);  
while (1) pause();
 
_exit(0);
 
break;
 
}
 
return 0;
 

 
 
Бұл  бағдарламаны  орындаудың  нәтижесінде  экранға  1  ден  10 
сандарының  тізбегі  шығады.  Егер  сигналдарды  үздіксіз  жіберілімдер 
арасында  жіберсек,  (sleep  (1)  шақыртуын  алып),  онда  сигналдарды 
жоғалту  қаупі  артады,  сондай  ақ  бұл  қауіп  артқан  сайын  жүйе 
процестің  орындалуымен  жүктеледі.  Бұл  жағдайда  сигналдарды 
жоғалту  1  ден  10  ға  дейін  емес,  ал  аз  санға  дейін  болуымен 
тұжырымдалады (мысалы, 8-ге дейін).
 
Бұл  бағдарламаның  негізгі  кемшілігі,  бұл  процесс  аралық  өзара 
әрекеттесудің  уақыты  өте  көп  және  уақыттың  біраз  бөлігін 
қабылдаушы-процесс сигнал күтумен алады. 
 
Жұмыс  уақытын  азайту  үшін  және  ақпарат  санын  арттыру  үшін 
уақыт  бірлігінде  сигналдар  көмегімен  жіберілетін,  олардың  арасында 
екі  бағытты  сигналдар  жіберілуін  ұйымдастыра  отырып,  қабылдаушы 
мен  жіберушінің  орындалуын  үйлестіреді.  Сонымен  қатар,  жіберуші 
қабылдаушыға  сигнал  жібереді,  ал  қабылдаушы  сигналдарды 
қабылдауға дайын және келесі сигналды өңдей алатынын хабарлаушы 
жауап-сигналдарын  жібереді.  Өндірілмейтін  кідірістер  мұндай  схема 
кезінде, өзара әрекеттесу минимумға түседі. 
 
Келесі  үлгіде  жіберуші-процес,  қабылдаушы-процеске  сигналдар 


207 
 
 
өңдеушісін орнату үшін (өңдеушілерді орнату үшін қажет, милисекунд 
бірлігінен  азды-  көпті  нақты  уақыт),  сигналдар  жіберу  алдында  5  сек 
күтеді.  Жіберуші  мен  қабылдаушы  арасындағы  ары  қарай  өзара 
әрекеттесуі  екі  бағытты    —  жіберуші  SIGINT  сигналын  жібереді, 
қабылдаушы  hdlrInt()  функциясы  арқылы  сигналды  өңдейді,  өңдеуші 
қалпына  келтіреді  және  жіберушіге  SIGALRM  қабылдаушының 
дайындығын куәландыратын сигнал –жауабын жібереді: 
 
#include 
 /*  Linux-ке қажет емес */
 
#include 
 
#include 
 
#include  
 
int num; 
 
void hdlrInt(int sig_no)
 
{
 
signal(sig_no, &hdlrInt);  
num++;
 
printf("%d\n", num);
 
}
 
void hdlrAlarm(int sig_no)
 
{
 
signal(sig_no, &hdlrAlarm);
 
}
 
int main()
 
{
 
pid_t pid;  
int i; 
 
setvbuf(stdout,(char*)NULL,_IONBF,0); 
 
switch ( pid = fork() )
 
{
 
case -1:
 
perror("Fork error\n");
 
_exit(1); break; case 0:
 
signal(SIGALRM, &hdlrAlarm);
 
sleep(5); /* қабылдаушының инилизациясын күтеді */  
for (i=0; i<10; i++)
 
{
 
kill(getppid(), SIGINT); /* SIGINT жібереміз */ 
pause(); /* Ждем SIGALRM */
 


 
208 
 
}
 
kill(getppid(), SIGTERM); /* қабылдауды аяқтаймыз */
 
_exit(0); /* жіберуді аяқтаймыз */
 
break;
 
default:
 
signal(SIGINT, &hdlrInt);  
while (1)
 
{
 
pause(); /* Ждем SIGINT */
 
kill(pid, SIGALRM); /* hdlrInt-тен қайту */
 
/* және жауап жібереміз */
 
}
 
_exit(0);
 
break;
 
}
 
return 0;
 

 
Келтірілген  үлгі  әдейі  қарапайымдандырылған.  Келесіге  назар 
аударған жөн, қабылдаушы да жіберуші де тек SIGALRM және SIGINT 
сигналдарымен  ғана  емес,  кез  келген  сигналмен  үзіліс  жағдайынан 
(pause()  функциясы  кезінде)    шығып  кетуі  мүмкін.  Дұрыс  жұмыс 
жасауы  үшін  қалған  сигналдар  сигналды  перденің  көмегімен  не 
SIG_IGN тұрақты шамалардың көмегімен еленбеуі қажет.   
 
 


Достарыңызбен бөлісу:
1   ...   176   177   178   179   180   181   182   183   ...   220




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

    Басты бет