Почему обработчик sigaction не обрабатывает каждый сигнал, даже если установлен флаг SA_NODEFER? - PullRequest
0 голосов
/ 11 мая 2018

У меня есть родительский процесс, который порождает десять дочерних процессов и использует обработчик SIGCHILD для уведомления о смерти дочернего процесса. Дочерние процессы уведомят, когда они начнутся, и сразу же завершат работу.
Я использую флаг SA_NODEFER для предотвращения отбрасывания сигналов SIGCHLD, когда поступает слишком много. Все дочерние элементы корректно завершаются и пожинаются, но в этом сценарии, а также при одновременном завершении двух одновременно через консольные сигналы, отправляемые в одно и то же время. время всегда появляется как единое целое.

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void CHLDHandler(int sig)
{
  char child[] = "Child finished!\n";
  write(1, &child, sizeof(child));
}

int main(int argc, char const *argv[]) {

  struct sigaction sa;
  sa.sa_handler = CHLDHandler;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_NODEFER;

  sigaction(SIGCHLD,&sa,NULL);

  for (size_t i = 0; i < 10; i++) {
    int pid = fork();

    if (pid == 0)
    {
      int pid = getpid();
      printf("I'm a child with pid %d!\n", pid);
      return 0;
    }
  }
  while(1)
  {
    wait(NULL);
  }

  return 0;
}

1 Ответ

0 голосов
/ 11 мая 2018

Базовые сигналы UNIX не ставятся в очередь - одновременно может ожидаться только один (для данного потока).

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

wait ing в цикле после получения SIGCHLD является давно установившейся техникой для компенсации того факта, что SIGCHLDможет быть "потерян".Переместите объявление «Дитя закончено! \ N» в цикл, который вызывает wait, и вы получите точный счет.

ОБНОВЛЕНИЕ

Если вы должны В самом обработчике вы можете вызвать wait внутри обработчика, поскольку он безопасен для асинхронного сигнала :

static void CHLDHandler(int sig)
{
  static char child[] = "Child finished!\n";
  int save_errno = errno;

  while (waitpid((pid_t)-1, NULL, WNOHANG) > 0) {
    write(STDERR_FILENO, &child, sizeof(child) - 1);  // don't write the terminating NULL
  }

  errno = save_errno;
}

В этом случае я бы не установите SA_NODEFER, поскольку другой SIGCHLD может прерывать (EINTR) вызовы waitpid или write.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...