`waitpid()'总是返回-1

时间:2019-04-21 17:28:05

标签: c linux unix waitpid

我正在执行下面的代码,对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 个答案:

答案 0 :(得分:1)

这里

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

如果不再存在子进程,则waitpid返回-1并使其始终while(true)并导致无限循环。

waitpid()的手册页中。

  

waitpid():成功后,返回其子进程的进程ID   状态已改变;如果指定了WNOHANG并且一个或多个   由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 */ 
}

答案 1 :(得分:1)

好吧,您误解了wait系统调用的工作原理。

malloc/free一样,每个waitpid()处理仅可以成功fork()一次...因此,如果您要等待,while循环就不再需要对于孩子的退出代码,您只需调用一次即可。在您的情况下,等待只会 返回-1,原因有两个:

  • fork()未成功,因此您正在等待无效的pid。实际上,您应该为wait()调用pid == -1,这是无效的。如果您wait()并且没有等待的过程(如果pid变量的值为正数,但是已经wait()的子过程中,您也会得到{{1} }),您会从任何-1系列系统调用中收到错误。 UN * X系统中 zombie 进程的任务就是这样,以确保已完成的子进程的wait()仍然有效,并且调用进程获取该子进程发出的退出代码在wait()上。
  • 您明确地说您不会等待过程完成。应该清楚的是,如果您不打算等待进程终止,那么您正在使用exit()参数,那么子进程可能仍在运行(这是您的情况),并且没有尚未完成WNOHANG的系统调用。如果子进程已经完成,则只需要退出代码。如果是这种情况,那么您最好编写:

    exit()

    while(waitpid(pid, &status, WNOHANG) == -1 && errno == EAGAIN) do_whatever_you_want_because_you_decided_not_to_wait(); 系统调用无法告知您wait变量没有用信号通知错误来填充子进程的退出代码,在这种情况下,它始终会设置&statuserrno

    但是,从我的角度来看,如果与此同时无事可做,那么最好不要使用EAGAIN。这样可以节省CPU周期并节省大量热能。