Уничтожение дочерних процессов из зависаний обработчика сигналов родителя - PullRequest
2 голосов
/ 29 октября 2011

У меня есть проблема в теме процессов posix, и я не могу обойтись.

У меня есть процесс, который разветвляется на несколько дочерних элементов (дерево процессов может быть сложным, а не только одного уровня).Он также отслеживает PID активных детей.В какой-то момент родитель получает сигнал (скажем, SIGINT).

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

  1. , если родительский объект не выполняет waitpid () для остановки дочернего элемента, кажется, что сигнал никогда не отправляется (зомби продолжают работать)
  2. , еслиparent ожидает после каждого kill (), отправленного потомку, он просто висит там, и потомок, кажется, игнорирует сигнал

Родитель и потомок имеют одинаковый обработчик сигнала, который устанавливается перед разветвлением.Вот псевдокод.

signal_handler( signal )
    foreach child in children
        kill( child, signal )
        waitpid( child, status )

    // Releasing system resources, etc.
    clean_up()

    // Restore signal handlers.
    set_signal_handlers_to_default()

    // Send back the expected "I exited after XY signal" to the parent by
    // executing the default signal handler again.
    kill( getpid(), signal )

С этой реализацией выполнение останавливается на waitpid.Если я уберу waitpid, дети продолжат работать.

Я предполагаю, что если обработчик сигналов не завершится, сигналы, отправленные с него, не будут отправлены детям.Но почему они не отправляются, если я опускаю ожидание?

Заранее большое спасибо!

1 Ответ

6 голосов
/ 03 ноября 2011

То, что вы описываете, должно работать и действительно работает со следующим тестовым примером:

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

#define NCHILDREN 3
pid_t child [NCHILDREN];

struct sigaction sa, old;

static void
handler (int ignore)
{
  int i;

  /* Kill the children.  */
  for (i = 0; i < NCHILDREN; ++i)
    {
      if (child [i] > 0)
        {
          kill (child [i], SIGUSR1);
          waitpid (child [i], 0, 0);
        }
    }

  /* Restore the default handler.  */
  sigaction (SIGUSR1, &old, 0);

  /* Kill self.  */
  kill (getpid (), SIGUSR1);
}

int
main ()
{
  int i;

  /* Install the signal handler.  */
  sa.sa_handler = handler;
  sigemptyset (&sa.sa_mask);
  sa.sa_flags = 0;
  sigaction (SIGUSR1, &sa, &old);

  /* Spawn the children.  */
  for (i = 0; i < NCHILDREN; ++i)
    {
      if ((child [i] = fork ()) == 0)
        {
          /* Each of the children: clear the array, wait for a signal
             and exit.  */
          while (i >= 0)
            child [i--] = -1;
          pause ();
          return 0;
        }
    }

  /* Wait to be interrupted by a signal.  */
  pause ();
  return 0;
}

Если вы видите, что родитель висит в waitpid, это означает, что ребенок не вышел. Попробуйте подключиться с помощью отладчика, чтобы увидеть, где заблокирован дочерний элемент, или, проще, запустите программу с strace(1). Как вы очищаете свой массив pid? Убедитесь, что дети не пытаются вызвать waitpid с параметром pid <= 0. Убедитесь, что дети не блокируют и не игнорируют сигнал. </p>

...