Отслеживание смерти дочернего процесса

Как я могу отследить смерть дочернего процесса, не заставляя родительский процесс ждать, пока дочерний процесс не будет убит?

Я пытаюсь сценарий клиент-сервер, где сервер принимает соединение от клиента и разветвляется новый процесс для каждого соединения, которое он принимает.

Я игнорирую сигналы SIGCHLD, чтобы предотвратить создание зомби.

signal(SIGCHLD, SIG_IGN);
while(1)
{
  accept();
  clients++;
  if(fork() ==0)
  {
     childfunction();
     clients--;
  }
  else
  {
  }
}

Проблема в приведенном выше сценарии заключается в том, что если дочерний процесс будет убит в функции childfunction () , глобальная переменная клиентов не уменьшается.

ПРИМЕЧАНИЕ: Я ищу решение без использования сигнала SIGCHLD ... Если возможно

20
задан codingfreak 8 March 2010 в 13:21
поделиться

3 ответа

Обычно вы пишете обработчик для SIGCHLD , который вызывает waitpid () для pid -1 . Вы можете использовать возвращаемое значение, чтобы определить, какой pid умер. Например:

void my_sigchld_handler(int sig)
{
    pid_t p;
    int status;

    while ((p=waitpid(-1, &status, WNOHANG)) != -1)
    {
       /* Handle the death of pid p */
    }
}

/* It's better to use sigaction() over signal().  You won't run into the
 * issue where BSD signal() acts one way and Linux or SysV acts another. */

struct sigaction sa;

memset(&sa, 0, sizeof(sa));
sa.sa_handler = my_sigchld_handler;

sigaction(SIGCHLD, &sa, NULL);

В качестве альтернативы вы можете вызвать waitpid (pid, & status, 0) с указанным идентификатором дочернего процесса и синхронно дождаться его смерти. Или используйте WNOHANG , чтобы проверить его статус без блокировки.

26
ответ дан 30 November 2019 в 00:13
поделиться

Вам не нужен зомби. Если дочерний процесс умирает, а родительский все еще RUNNING, но не выдает wait()/waitpid() вызов для сбора статуса, система не освобождает ресурсы, связанные с дочерним процессом, и в таблице proc остается зомби/неработающий процесс.

Попробуйте изменить ваш обработчик SIGCHLD на что-то более близкое к следующему:


void chld_handler(int sig) {
    pid_t p;
    int status;

    /* loop as long as there are children to process */
    while (1) {

       /* retrieve child process ID (if any) */
       p = waitpid(-1, &status, WNOHANG);

       /* check for conditions causing the loop to terminate */
       if (p == -1) {
           /* continue on interruption (EINTR) */
           if (errno == EINTR) {
               continue;
           }
           /* break on anything else (EINVAL or ECHILD according to manpage) */
           break;
       }
       else if (p == 0) {
           /* no more children to process, so break */
           break;
       }

       /* valid child process ID retrieved, process accordingly */
       ...
    }   
}

Вы можете опционально маскировать/блокировать дополнительные SIGCHLD сигналы во время выполнения обработчика сигнала, используя sigprocmask(). Заблокированная маска должна быть возвращена в исходное значение после завершения работы обработчика сигналов.

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

2
ответ дан 30 November 2019 в 00:13
поделиться

Переменная «клиенты» находится в разных адресных пространствах процесса после fork (), и когда вы уменьшаете переменную в дочернем элементе, это не повлияет на значение в родительском элементе. Я думаю, вам нужно обработать SIGCHLD, чтобы правильно обрабатывать счет.

0
ответ дан 30 November 2019 в 00:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: