`waitpid () 'всегда возвращает -1 - PullRequest
2 голосов
/ 21 апреля 2019

Я выполняю приведенный ниже код, и вызов waitpid() всегда возвращает -1, поэтому код ниже заканчивается бесконечным циклом.Вызов работает, если я заменю WNOHANG на 0.

void execute(cmdLine* pCmdLine) {
    int status = 0;
    pid_t pid = fork();
    if(pid == 0) {
         if(execvp(pCmdLine->arguments[0], pCmdLine->arguments) == -1) {
             if(strcmp(pCmdLine->arguments[0], "cd") != 0) {
               perror("execute failed\n");
             }
        _exit(1);
        }
    } else {
        if(pCmdLine->blocking == 1) {
            waitpid(pid, &status, 0);
        }
            while(waitpid(pid, &status, WNOHANG) == -1) {
             printf("still -1\n");
            }
         }     
    }
}

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

Что ж, вы неправильно поняли, как работает системный вызов wait.

Как и в случае malloc/free, вы можете waitpid() успешно только один раз за fork() обработанный процесс ... так чтоЦикл while никогда не нужен, если вы собираетесь ждать код выхода ребенка, вы должны вызывать его только один раз.Ожидание only вернет -1 в вашем случае по двум причинам:

  • fork() не удалось, поэтому вы ожидаете недопустимого pid.В самом деле, вы должны звонить wait() для pid == -1, что неверно.Если у вас wait() и нет ожидаемого процесса (в случае, если переменная pid имеет положительное число, но для уже обработанного wait() подпроцесса вы также получаете -1), вы получаете сообщение об ошибкелюбой из семейства системных вызовов wait().Задача процессов zombie в системах UN * X заключается в том, чтобы гарантировать, что wait() для уже законченного дочернего элемента все еще действует, и вызывающий процесс получает код выхода, сообщенный дочерним элементом на exit().
  • Вы прямо говорите, что не собираетесь ждать завершения процесса.Должно быть понятно, что если вы не собираетесь ждать завершения процесса, это то, что вы делаете с параметром WNOHANG, тогда дочерний процесс может все еще выполняться (как в вашем случае) и еще не был выполнен.exit() системный вызов.Код выхода требуется только в том случае, если дочерний процесс уже завершен.Если это так, то вам лучше написать:

    while(waitpid(pid, &status, WNOHANG) == -1 && errno == EAGAIN)
        do_whatever_you_want_because_you_decided_not_to_wait();
    

    Системный вызов wait не может сообщить вам, что переменная &status не была заполнена кодом выхода издочерний процесс, чем сигнал об ошибке, и в этом случае он всегда устанавливает errno в EAGAIN.

    но, с моей точки зрения, если вам пока нечего делать, то вам лучше не использовать WNOHANG.Это сэкономит циклы процессора и много тепловой энергии, выбрасываемой в окружающую среду.

1 голос
/ 21 апреля 2019

Здесь

 while(waitpid(pid,&status,WNOHANG)==-1) { }

если не существует дочернего процесса, то waitpid возвращает -1, и он всегда делает while(true), что вызывает бесконечный цикл.

со страницы руководства waitpid().

waitpid(): в случае успеха возвращает идентификатор процесса ребенка, чей состояние изменилось ; если был указан WNOHANG и один или несколько child (ren), заданный pid, существует, но еще не изменил состояние, тогда 0 возвращается. При ошибке возвращается -1.

Это означает, что когда больше нет дочерних элементов, ожидающих, возвращается -1. Так что либо сделай это как

if() { /* child process. can be multiple */
} 
else { /* parent process */
    while(waitpid(pid,&status,WNOHANG) != -1) { /* when there is no more child process exists then it terminate */ 
    }
}

или

if() { /* child process. can be multiple */
} 
else { /* parent process */
  while(waitpid(pid,&status,WNOHANG) == -1);  /* dummy while ..when there is no more child process exists then it terminate */ 
}
...