Почему дочерний процесс не продолжает работать после получения сигнала? - PullRequest
3 голосов
/ 25 сентября 2011

Ниже приведен мой код. Родитель разветвляет ребенка. Дочерняя пауза, пока родитель не отправит ему сигнал, затем он продолжит работу. Мой вопрос: почему дочерний процесс не продолжается? работает после того, как родитель отправил ему сигнал. Я что-то упустил или неправильно понял?

#include<stdio.h>
#include<unistd.h>
#include<signal.h>


void 
sigusr1( int pidno )
{
  printf("Catched\n");
}

int 
main()
{
  pid_t pid;

  signal( SIGUSR1, sigusr1 );
  if( (pid = fork()) == 0 ){
    pause();
  printf("Child\n"); 
  }

  kill( pid , SIGUSR1 ); //parent sends signal to child 
  pause();
}

Ответы [ 2 ]

3 голосов
/ 25 сентября 2011

Вот что происходит у родителя:

  1. Вилка ребенка.
  2. Отправьте SIGUSR1 ребенку.
  3. Дождитесь сигнала.

Вот что происходит с ребенком:

  1. Ждать сигнала.
  2. Печать Child.
  3. Позвоните kill(0, SIGUSR1) (0 - значение pid для ребенка). Вызов kill с идентификатором процесса 0 отправляет сигнал каждому процессу в группе процессов процесса, который вызывает kill.
  4. Дождитесь сигнала.

Существует несколько возможных вариантов поведения вашей программы в зависимости от порядка выполнения родительского и дочернего системных вызовов. В зависимости от конкретной версии вашей операционной системы, от точной настройки различных параметров ядра, от того, насколько загружена ваша система, и от случайного выбора, вы можете или не можете наблюдать различное поведение, если вы запускаете программу несколько раз или под отладчик.

Если родитель начинает быстрее, чем ребенок, вы можете увидеть это:

  1. Родитель отправляет SIGUSR1 ребенку.
  2. Ребенок получает SIGUSR1 и печатает Catched.
  3. ребенок звонит pause.
  4. Родительские звонки pause.

При таком порядке выполнения родитель и потомок в конечном итоге ждут вечно (это тупик ).

Если ребенок начинает быстрее, чем родитель, вы можете увидеть это:

  1. Ребенок звонит pause.
  2. Родитель отправляет SIGUSR1 ребенку.
  3. Родительские звонки pause.
  4. Ребенок разблокирован и печатает Catched.
  5. Отпечатки детей Child.
  6. Child отправляет SIGUSR1 в группу процессов.
  7. Детские принты Catched.
  8. ребенок звонит pause.
  9. Родитель разблокирован и печатает Catched.
  10. родительский выход.

Я не думаю, что у ребенка есть способ выйти: он дважды вызывает pause, и хотя он может получить до двух сигналов, один из них отправляется от самого себя (тот, что из kill(0,SIGUSR1)) и тот доставляется синхронно, а не во время выполнения pause.

Эта программа, вероятно, не та, что вы хотели написать, но, поскольку вы не описываете ожидаемое поведение, невозможно сказать, что вы хотели написать. Замечу, что вы не следуете обычной структуре программы, которая разветвляется:

pid = fork();
if (pid < 0) {
    /*error handling*/
} else if (pid == 0) {
    /*child code*/
    exit(...); /*Usually, what follows the if is specific to the parent.*/
}
1 голос
/ 25 сентября 2011

Попробуйте:

#include<stdio.h>
#include<unistd.h>
#include<signal.h>


void
sigusr1( int pidno )
{
  fprintf(stderr, "Caught\n");
}

int
main()
{
  pid_t pid;

  signal( SIGINT, sigusr1 );
  if( (pid = fork()) == 0 ){
    pause();
    fprintf(stderr, "Child\n");
  }
  else
  {
    fprintf(stderr, "Parent\n");
    kill( pid , SIGINT ); //parent sends signal to child
  }
  pause();
  return 0;
}
  1. printf буферизует ввод: возможно, он вызывается, но не отображается, когда вы ожидаете.Один обходной путь - fflush().Лучший обходной путь - fprintf (stderr), который не буферизируется в первую очередь.

  2. Вы вызываете kill() как в родительском, так и в дочернем элементахЯ добавил else, чтобы устранить это.

  3. Вот пример вывода:

gcc -Wall -g -o z z.c

./z
Parent
Caught
Child
...