2016-11-05 2 views
0

Я учусь связи между процессами в Linux, используя убить() для передачи сигналов на спящий ребенок process.Here моей программа:Почему мой обработчик сигнала выполняет дважды?

8 void func(void); 
9 int main(void){ 
10   int i, j; 
11   pid_t status, retpid; 
12   signal(17,func); 
13   if(i = fork()){ 
14     printf("Parent:signal 17 will be sent to child!\n"); 
15     kill(i, 17); 
16     wait(0); 
17     printf("child process terminated\n"); 
18     } 
19   else{ 
20     sleep(10); 
21     printf("Child: A signal from my parent is received!\n"); 
22     exit(0); 
23   } 
24 } 
25 void func(void) 
26 { 
27   printf("the signal has been sent!\n"); 
28 } 

Собран с НКОЙ, программа производства аномального результата, в котором функ () выполняется дважды:

./test4.out 
Parent:signal 17 will be sent to child! 
the signal has been sent! 
Child: A signal from my parent is received! 
the signal has been sent! 
child process terminated 

Я проанализировал результат, а затем удаляется следующие две строки:

16     wait(0); 
17     printf("child process terminated\n"); 

и результат б ecame normal, с func(), вызываемым только один раз. Похоже, что виновником является функция wait(), но почему она когда-либо вызывала обработчик сигнала?

+0

** Может быть **, когда родительский процесс закрывается, он ждет сигнала KILL из процесса-жнеца ...? После завершения процесса он не умирает. Он остается до тех пор, пока не будет завершен «обманщик» (либо владелец, либо системный процесс, отвечающий за получение процессов зомби). Это может быть сигнализация жнеца, что это сделано. – Myst

+3

'printf' не является сигнальной функцией и не должен вызываться в обработчике сигнала. Возможное объяснение состоит в том, что он вызывает неопределенное поведение (например, дважды очищает буфер толстого хода - один раз в обработчике сигнала и один раз, когда процесс завершается). – kaylum

+1

, пожалуйста, отправьте текстовый код, а не с добавленными номерами строк. Мы не можем просто захватить опубликованный код и вставить его в наши редакторы, не выполняя много строк за строкой. Не используйте вкладки для отступов, так как каждый текстовый редактор/редактор имеет ширину табуляции/ширину табуляции, заданную для индивидуальных предпочтений. Даже после исправления проблемы с номером строки, опубликованный код не компилируется. Кажется, что отсутствуют необходимые инструкции '# include' – user3629249

ответ

0

после коррекции (большинство) ошибок в размещенном коде ..

Результат является следующий код:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/wait.h> 

void func(int); 

int main(void) 
{ 
    pid_t i; 
    //pid_t status; 
    //pid_t retpid; 
    signal(17,func); 


    if((i = fork())) 
    { 
     printf("the fork'd child pid:%d\n", i); 
     printf("Parent:signal 17 will be sent to child!\n"); 
     kill(i, 17); 
     wait(NULL); 
     printf("child process terminated\n"); 
    } 

    else 
    { 
     sleep(10); 
     printf("Child: pid:%d\n", getpid()); 
     exit(0); 
    } 
} 

void func(int theSignal) 
{ 
    if(17 == theSignal) 
    { 
     fprintf(stdout, "the 17 signal has been processed by %d!\n", getpid()); 
    } 

    else 
    { 
     fprintf(stdout, "the %d signal is processed\n", theSignal); 
    } 
} 

и выход:

the fork'd child pid:4845 
Parent:signal 17 will be sent to child! 
the 17 signal has been processed by 4845! 
Child: pid:4845 
the 17 signal has been processed by 4844! 
child process terminated 

Который ясно показывает, что как родительский, так и дочерний процесс обрабатывают сигнал

EDIT:

Однако, когда уникальное значение SIGUSR2 используются как в следующем коде:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/wait.h> 

void func(int); 

#define MY_SIGNAL (31) 

int main(void) 
{ 
    pid_t i; 
    //pid_t status; 
    //pid_t retpid; 
    signal(17,func); 
    signal(31,func); 

    if((i = fork())) 
    { 
     printf("the fork'd child pid:%d\n", i); 
     printf("Parent:signal %d will be sent to child!\n", MY_SIGNAL); 
     kill(i, MY_SIGNAL); 
     wait(NULL); 
     printf("child process terminated\n"); 
    } 

    else 
    { 
     sleep(10); 
     printf("Child: pid:%d\n", getpid()); 
     exit(0); 
    } 
} 

void func(int theSignal) 
{ 
    if(MY_SIGNAL == theSignal) 
    { 
     printf("the %d signal has been processed by %d!\n", MY_SIGNAL, getpid()); 
    } 

    else 
    { 
     printf("the %d signal is processed\n", theSignal); 
    } 
} 

, то выход есть:

the fork'd child pid:5099 
Parent:signal 31 will be sent to child! 
the 31 signal has been processed by 5099! 
Child: pid:5099 
the 17 signal is processed 
child process terminated 

, который четко показывает ребенок обработанного сигнала 31 (SIGUSR2) и родительский обработанный сигнал 17 (SIGCHLD)

+1

У этого по-прежнему есть ошибка вызова функции, не требующей сигнализации, из обработчика сигнала. –

+0

Я сказал, что исправил «МОСТ» ошибки в размещенном коде. Цель моего ответа состояла в том, чтобы не инструктировать/не продемонстрировать, как писать обработчик сигнала, а скорее показать, почему обработчик сигнала выполняется более одного раза – user3629249

+0

ПРИМЕЧАНИЕ: причина, по которой родитель получает сигнал, состоит в том, что SIGCHLD также имеет значение 17 что означает, что значение не является уникальным. Если бы OP использовал 31, для SIGUSER2, то он был бы уникальным. Я отредактировал ответ, чтобы показать это отношение – user3629249

2

Вы передаете сигнал 17 дочернему процессу, поэтому его обработчик вызывается, как ожидалось.

Сигнал 17 - SIGCHLD. SIGCHLD отправляется родительскому процессу, когда дочерний процесс умирает. Обработчик родителя вызывается, когда ребенок завершает работу. Этот сигнал не поступает от родителя; он приходит из ОС, чтобы уведомить родителя о смерти ребенка.

Смежные вопросы