我正在执行下面的代码,对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");
}
}
}
}
答案 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
变量没有用信号通知错误来填充子进程的退出代码,在这种情况下,它始终会设置&status
至errno
。
但是,从我的角度来看,如果与此同时无事可做,那么最好不要使用EAGAIN
。这样可以节省CPU周期并节省大量热能。