Сон не работает в дочернем процессе после вызова функции popen - PullRequest
0 голосов
/ 15 апреля 2019

Я написал небольшую программу на C, которая создает дочерний процесс и затем запускает команду оболочки с помощью popen.Я создал обработчик сигнала для ожидания завершения дочернего процесса, пока родительский процесс просто выполняется в бесконечном цикле.Когда я вызываю «sleep (5)» после системного вызова popen, «sleep» не работает.

Вместо этого, если я помещаю вызов в спящий режим перед всплывающим окном, он работает.Кроме того, если я удаляю обработчик сигнала и просто жду дочерний процесс в родительском процессе, то проблем не возникает (т. Е. Режим сна работает в любом месте).

//Assume all required header files and function prototypes added

int main()
{
    int pid,status;
    signal(SIGCHLD,reaper);
    pid = fork();
    if(pid == 0)
       runCommand();
    while(1);
}

void runCommand()
{
    FILE *pipen;
    char *buffer;

    buffer = (char*) malloc(100);
/*sleep #1*/    sleep(5);
    if ((pipen = popen("uname -a", "r")) == NULL) {
        perror("\nError during shell command execution: ");
        exit(0);
    }
/*sleep #2*/    sleep(5);
    fgets(buffer, 100, pipen);
/*sleep #3*/    sleep(5);
    printf("\n%s\n",buffer);
    exit(0);
}

void reaper(int signal)
{
    int status;
    waitpid(-1,&status,WNOHANG);
}

Когда я запускаю вышеуказанную программу sleep # 1работает и процесс спит на данное время.Я узнаю об этом, наблюдая за временем, которое требуется для вывода результата команды (оператором printf).Но для сна № 2 и сна № 3 я ожидаю, что процесс будет спать, но, похоже, этого не происходит, так как результат команды выводится на консоль мгновенно.

Поведение можно наблюдать, сохраняя тольковызов sleep # 2 или sleep # 3 и удаление двух других вызовов sleep.

Кто-нибудь знает, почему это происходит?

1 Ответ

3 голосов
/ 16 апреля 2019

popen() работает, заставляя ребенка выполнить /bin/sh -c "uname -a".Когда этот потомок выходит, процесс получает сигнал SIGCHLD.Это прерывает вызов sleep() и запускает вашу функцию reaper.

Я не смог найти это упомянутое ни в одной документации Linux или POSIX, но это в документации SunOS :

При использовании popen() обработчик сигнала для SIGCHLD должен быть установлен по умолчанию.Если процесс установил обработчик сигнала для SIGCHLD, он будет вызван после завершения команды.Если обработчик сигнала или другой поток в том же процессе выполняет вызов wait(2), он будет мешать возвращаемому значению pclose().Если обработчик сигнала процесса для SIGCHLD был настроен на игнорирование сигнала, pclose() завершится ошибкой, а для errno будет установлено значение ECHILD.

Вам следует установить обработчик SIGCHLD обратнопо умолчанию в дочернем процессе.

void runCommand()
{
    FILE *pipen;
    char *buffer;

    signal(SIGCHLD, SIG_DFL);

    buffer = (char*) malloc(100);
/*sleep #1*/    sleep(5);
    if ((pipen = popen("uname -a", "r")) == NULL) {
        perror("\nError during shell command execution: ");
        exit(0);
    }
/*sleep #2*/    sleep(5);
    fgets(buffer, 100, pipen);
/*sleep #3*/    sleep(5);
    printf("\n%s\n",buffer);
    exit(0);
}
...