Обработка зомби с SIGCHLD - PullRequest
       11

Обработка зомби с SIGCHLD

0 голосов
/ 19 апреля 2020

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

Код:

void myhandler(int signo)
{   
    printf("test");
    int status;
    pid_t pid;

    while((pid = waitpid(-1, &status, WNOHANG)) > 0)
        ++count;
}

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

    struct sigaction sigchld_action;
    memset(&sigchld_action,0,sizeof(sigchld_action));
    sigchld_action.sa_handler = &myhandler;
    sigaction(SIGCHLD,&sigchld_action,NULL);

    if(fork() == 0){
        exit(0);
    }
    if(fork()==0){
        exit(0);
    }
    if(fork()==0){
        exit(0);
    }


    while(wait(NULL) > 0)
    ++count;

    return 0;
}

Проблема в том, что число разветвленных дочерних элементов и количество выходных данных printf (" test ") иногда не совпадает. Количество разветвленных потомков больше числа printf («test»).

Гарантирует ли этот сегмент кода, что зомби не будет? Если да, то как этого добиться? Это не печать правильного номера «теста». Неужели waitpid () очищает мертвых потомков более одного раза за это время?

Что происходит, когда вызывается этот обработчик сигнала, в то же время может умереть другой ребенок. Сигнал будет заблокирован по умолчанию (во время работы обработчика другой ребенок может d ie). Очищает ли waitpid процесс, сигнал которого отправляется, когда работает обработчик сигнала?

Кроме того, счетчик не равен. (stati c volatile int) или я попробовал атоми c целое число.

1 Ответ

1 голос
/ 19 апреля 2020

Происходят две разные вещи:

  1. printf не является асинхронным c -signal-safe, поэтому вы не должны вызывать его из обработчика сигнала. Замените его на write.
  2. Вы увеличиваете count только один раз в обработчике сигнала. Если вы хотите узнать, сколько процессов умерло, вам нужно увеличить его в while l oop.

Попробуйте этот код:

void handler(int signo)
{   
    int status;
    pid_t pid;
    while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        write(1, "test", 4); /* technically this may result in a partial write and you should loop it, but in practice I think this'll be fine for this example */
        ++count;
    }
}

С этим код, вы, вероятно, не будете иметь зомби и будете иметь правильное число test с и правильное значение в count. Однако есть еще одно условие гонки: если между последним вызовом waitpid и концом обработчика сигнала другой дочерний процесс умирает, то SIGCHLD не будет получено, поэтому он будет зомби ie до один после этого тоже умирает. Решение этого крайнего случая гораздо сложнее и зависит от того, как структурирована остальная часть вашего приложения.

...