waitpid с execl, используемым в дочернем элементе, возвращает -1 с ECHILD?

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

Когда я использую waitpid в родительском, он дает мне дочерний процесс, поскольку возвращаемое значение из waitpid равно 0. Через некоторое время я пытаюсь использовать waitpid в другой функции, где она возвращает мне -1 с ECHILD. Когда я должен использовать waitpid, если я не уверен, что ребенок погоды завершен или нет?

//pid_t Checksum_pid = fork();
Checksum_pid = fork();

if (Checksum_pid == 0)
{
    execl(path, name, argument as needed, ,NULL);
    exit(EXIT_SUCCESS);     
}
else if (Checksum_pid > 0)
{ 
    pid_t returnValue = waitpid(Checksum_pid, &childStatus, WNOHANG);

    if ( returnValue > 0)
    {
        if (WIFEXITED(childStatus))
        {
            printf("Exit Code: _ WEXITSTATUS(childStatus)") ;               
        }
    }
    else if ( returnValue == 0)
    {
        //Send positive response with routine status running (0x03)
        printf("Child process still running") ; 
    }
    else
    {
        if ( errno == ECHILD )
        {
             printf(" Error ECHILD!!") ;
        } 
        else if ( errno == EINTR )
        {
            // other real errors handled here.
            printf(" Error EINTR!!") ;
        }
        else
        {
            printf("Error EINVAL!!") ;
        }       
    }
}
else
{   
    /* Fork failed. */
    printf("Fork Failed") ;
}

person kapilddit    schedule 27.03.2014    source источник
comment
exit(EXIT_SUCCESS); после execl() — неверный индикатор; если execl() возвращается, это значит, что он потерпел неудачу, поэтому вам действительно следует выйти с exit(EXIT_FAILURE);, чтобы сообщить родительскому процессу, что вы потерпели неудачу.   -  person Jonathan Leffler    schedule 27.03.2014
comment
Когда я пытаюсь использовать printf в дочернем процессе выше execl и ниже execl. Мне не удалось получить отпечатки... Не знаю почему. Я думаю, что выше execl я должен получить печать. Я пишу? Если execl успешен, то как выйти из дочернего процесса, чтобы завершить его? Если я использую waitpid не в родительском процессе (где-то в другой функции после некоторого выполнения), то допустимо ли использовать waitpid с тем же дочерним идентификатором, что и первый аргумент, который я получил в родительском процессе?   -  person kapilddit    schedule 27.03.2014


Ответы (3)


Если вы ждете с WNOHANG, то вы не получите никакого полезного статуса, если только ваш ребенок уже не умер — и, возможно, он еще даже не начал работу (он все еще может ожидать загрузки исполняемого файла с диска, когда родитель выполняет waitpid()).

Если вы хотите знать, что дочерний процесс завершен, не используйте WNOHANG — используйте 0 в качестве третьего аргумента, если вы не хотите знать о неотслеживаемых или продолжающихся процессах. Это будет ждать, пока процесс, указанный Checksum_pid, не завершится, или система не потеряет его из виду каким-то загадочным образом (чего я никогда не видел).


Этот код выдает Exit Code: 0 в качестве вывода:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    pid_t Checksum_pid = fork();

    if (Checksum_pid < 0)
        printf("Fork Failed\n");
    else if (Checksum_pid == 0)
    {
        execl("/bin/sleep", "/bin/sleep", "2", NULL);
        exit(EXIT_FAILURE);
    }
    else
    {
        int childStatus;
        pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);

        if (returnValue > 0)
        {
            if (WIFEXITED(childStatus))
                printf("Exit Code: %d\n", WEXITSTATUS(childStatus));
            else
                printf("Exit Status: 0x%.4X\n", childStatus);
        }
        else if (returnValue == 0)
            printf("Child process still running\n");
        else
        {
            if (errno == ECHILD)
                printf(" Error ECHILD!!\n");
            else if (errno == EINTR)
                printf(" Error EINTR!!\n");
            else
                printf("Error EINVAL!!\n");
        }
    }

    return 0;
}

Это очень похоже на ваш код; Я просто переместил проверку fork() наверх. Я бы все же предпочел избавиться от "густых деревьев" операторов if, но это не критично. Что происходит, когда вы запускаете этот код? Что вам нужно изменить, чтобы получить ошибку ECHILD (можете ли вы изменить это, чтобы получить ошибку ECHILD)?

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

Протестировано на Mac OS X 10.9.2 Mavericks с GCC 4.8.2, а также на Ubuntu 13.10 с GCC 4.8.1 (мне нужно было добавить -D_XOPEN_SOURCE=700, чтобы он компилировался с моими строгими флагами компиляции; Mac OS X обходилась без этого), но Я не ожидаю получить другие результаты в другом месте.

person Jonathan Leffler    schedule 27.03.2014
comment
Тогда что мне нужно использовать? В чем смысл, если я передам 0 в качестве необязательного третьего аргумента вместо WNOHANG? - person kapilddit; 27.03.2014
comment
Какие аргументы мне нужно использовать в waitpid? Я пробовал с WCONTINUED, но безуспешно. Должен ли я использовать WUNTRACED? - person kapilddit; 27.03.2014
comment
Я пробовал с 0 в качестве третьего аргумента для waitpid, но все равно выдавал ОШИБКУ: ECHILD!! Если выход (0) в дочернем процессе означает, что он будет завершен с кодом выхода 0? Здесь В моем случае execl выполняется успешно. - person kapilddit; 27.03.2014
comment
У меня есть два набора функций: 1) start: в котором я хочу использовать execl в дочернем процессе, который будет выполнять файл сценария и генерировать выходной файл. 2) parse_display_res: в этой функции я буду использовать сгенерированный выходной файл (из функции запуска) для извлечения результата. Поэтому перед извлечением данных необходимо иметь выходной файл. - person kapilddit; 27.03.2014
comment
Вы можете вернуться к старому int corpse = wait(&status);, который просто ждет смерти ребенка и сообщает об этом или возвращает -1, если детей не осталось. В противном случае опубликуйте полный SSCCE (Короткий, автономный, правильный пример) или MCVE ([Минимальный, полный, проверяемый Пример](http:stackoverflow.com/help/mcve)) кода проблемы (например, настроен для запуска sleep 5 в качестве дочернего процесса). - person Jonathan Leffler; 27.03.2014
comment
Я использовал int return_value = wait(&child_status); Все еще ошибка ECHILD с возвращаемым значением -1 из ожидания. Когда я удалил execl (с waitpid) из дочернего процесса, он показывает, что дочерний процесс все еще работает. Как я могу узнать, что ребенок успешно закончил? Я не знаю, почему ребенок прерывается ненормально. - person kapilddit; 28.03.2014
comment
@ Джонатан Леффлер Я скопировал тот же код, который вы предложили здесь. Я тестировал то же самое на Ubuntu, он работает, как вы и ожидали, как вы описываете, но когда я пробую тот же код на своей цели, это дает мне ошибку: waitpid возвращает -1 с ECHILD. ты хоть представляешь, как это могло случиться? - person kapilddit; 07.04.2014
comment
Короче говоря, нет — я понятия не имею, как вы получаете ECHILD. На какой платформе вы работаете? Вы хотите сказать, что приведенная выше программа выдает результат ECHILD? Или вы пытались использовать мой код в своей программе, и он выдал результат ECHILD? Вам нужно опубликовать свой MCVE (Как создать минимальный, полный и проверяемый пример?) или SSCCE (Короткий, автономный, правильный пример) вместе с информацией для идентификации вашей платформы и компилятора. - person Jonathan Leffler; 07.04.2014

Если сигнал SIGCHLD игнорируется (по умолчанию) и вы пропускаете WNOHANG, как упоминалось Джонатаном, то waitpid будет зависать до тех пор, пока дочерний процесс не завершится, а затем произойдет сбой с кодом ECHILD. Я сам столкнулся с этим в сценарии, когда родительский процесс просто должен дождаться завершения дочернего процесса, и регистрация обработчика для SIGCHLD казалась излишней. Естественным последующим вопросом будет: «Можно ли рассматривать ECHILD как ожидаемое событие в этом случае, или я всегда должен писать обработчик для SIGCHLD?», но на этот вопрос у меня нет ответа.

Из документации для waitpid(2):

ЭЧИЛД

(для waitpid() или waitid()) Процесс, указанный в pid (waitpid()) или idtype и id (waitid()), не существует или не является дочерним по отношению к вызывающему процессу. (Это может произойти для собственного потомка, если действие для SIGCHLD установлено в SIG_IGN. См. также раздел Linux Notes о потоках.)

и далее вниз

В POSIX.1-2001 указано, что если для SIGCHLD задано значение SIG_IGN или для SIGCHLD установлен флаг SA_NOCLDWAIT (см. ) будет блокироваться до тех пор, пока не будут завершены все дочерние процессы, а затем завершится сбоем, когда для errno будет установлено значение ECHILD. (Исходный стандарт POSIX оставил поведение установки SIGCHLD в SIG_IGN неопределенным. Обратите внимание, что хотя по умолчанию SIGCHLD настроен на «игнорирование», явная установка SIG_IGN приводит к другому обращению с дочерними процессами-зомби.) Linux 2.6 соответствует этому Технические характеристики. Однако в Linux 2.4 (и более ранних версиях) этого не происходит: если вызов wait() или waitpid() выполняется, когда SIGCHLD игнорируется, вызов ведет себя так же, как если бы SIGCHLD не был проигнорирован, то есть вызов блокируется до следующего дочерний процесс завершается, а затем возвращает идентификатор процесса и статус этого дочернего процесса.

См. также этот ответ.

person luen    schedule 06.07.2014

person    schedule
comment
Изучите, как создать MCVE Как создать минимальный, полный и проверяемый пример? или SSCCE (Короткий, автономный, правильный пример), два названия для одной и той же основной идеи. Что такое g_area в приведенном выше коде? Каково значение ScriptPath и ScriptName? Какое значение Area вы передали? Почему ни одно из ваших сообщений не заканчивается новой строкой (они не будут надежно отображаться, пока не сделают это). Почему в коде так много пустых строк? Почему бы вам не распечатать значение WEXITSTATUS вместо включения имени макроса в вывод? - person Jonathan Leffler; 28.03.2014