Fork / exec, оставляющий процессы-зомби даже с сигналом

#c #signals #fork #exec #zombie-process

#c #сигналы #fork #exec #зомби-процесс

Вопрос:

У меня есть сама программа-демон fork , которая затем выполняет бесконечный цикл проверки системных условий, и когда выполняются определенные условия, она запускает команду. Эти команды могут выполняться долго, что означает, что они должны быть асинхронными, поэтому я использую fork и execvp для выполнения команд. Мой код выглядит так:

 int main(int argc, char *argv[])
{
  signal(SIGCHLD, SIG_IGN);
  pid_t pid, sid;
  pid = fork();
  if (pid < 0)
  {
    exit(EXIT_FAILURE);
  }
  if (pid > 0)
  {
    exit(EXIT_SUCCESS);
  }
  umask(0);
  sid = setsid();
  if (sid < 0)
  {
    exit(EXIT_FAILURE);
  }
  if ((chdir("/")) < 0)
  {
    exit(EXIT_FAILURE);
  }
  while (1)
  {
    // Check conditions
    ...
    if (conditions_met)
    {
      pid_t pid2, sid2;
      pid2 = fork();
      if (pid2 == 0)
      {
        sid2 = setsid();
        // Define command_argv
        ...
        execvp(command_argv[0], command_argv);
      }
    }
  sleep(60);
  }
exit(EXIT_SUCCESS);
}
  

Все это работает, и мои команды выполняются нормально — однако это оставляет процессы-зомби. Я впервые пытаюсь использовать fork и exec асинхронно, но я подумал, что signal(SIGCHLD, SIG_IGN) это должно игнорировать дочерний элемент и позволить процессам инициализации пожинать их. Почему эти зомби все еще задерживаются?

Ответ №1:

SIG_IGN Настройка не сохраняется fork() , поэтому вам нужно вызвать signal(SIGCHLD, SIG_IGN); дочерний процесс с циклом, который порождает все команды, а не исходный родительский процесс.

 #include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
    pid_t pid, sid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (pid > 0)
    {
        exit(EXIT_SUCCESS);
    }
    signal(SIGCHLD, SIG_IGN);
    umask(0);
    sid = setsid();
    if (sid < 0)
    {
        perror("setsid");
        exit(EXIT_FAILURE);
    }
    if ((chdir("/")) < 0)
    {
        perror("chdir");
        exit(EXIT_FAILURE);
    }
    while (1)
    {
        // Check conditions
        if (true)
        {
            pid_t pid2, sid2;
            pid2 = fork();
            if (pid2 == 0)
            {
                sid2 = setsid();
                // Define command_argv
                execlp("sleep", "sleep", "1", (char*)0);
            }
        }
        sleep(60);
    }
    exit(EXIT_SUCCESS);
}