C++ Linux、waitpid、WNOHANG和僵尸
我需要能够:C++ Linux、waitpid、WNOHANG和僵尸,c++,c,fork,wait,waitpid,C++,C,Fork,Wait,Waitpid,我需要能够: 分叉一个进程并使其执行(我做到了) 检查子进程execvp是否成功(不知道如何成功) 检查子进程是否已完成(存在问题) 我正在分岔一个过程,我没有任何方法来检查孩子的execvp是否有效或失败。如果它失败了,我需要知道它失败了。目前我正在使用 -1 != waitpid( pid, &status, WNOHANG ) 但是,如果pid进程的execv失败,waitpid似乎不会返回-1 我怎么能检查呢?我读了waitpid手册页,但我不清楚;也许我的英语不够好 编辑:为
-1 != waitpid( pid, &status, WNOHANG )
但是,如果pid进程的execv失败,waitpid似乎不会返回-1
我怎么能检查呢?我读了waitpid手册页,但我不清楚;也许我的英语不够好
编辑:为了解释更多内容:我正在为家庭作业建造自己的终端。我需要输入一个命令字符串,比如“ls”,然后我必须执行该命令。
在子fork之后,子对象调用execvp以执行命令(在我解析字符串之后),父对象需要检查命令末尾是否有“&”。
如果命令末尾不存在符号“&”,则父级需要等待子级执行
所以我需要知道execvp是否失败了。如果没有失败,则父级使用waitpid等待子级完成执行。如果失败,则父进程将不等待子进程。如果执行成功,则不应返回exec调用,因为它将用另一个进程映像替换当前进程映像,因此如果执行成功,则表示发生了错误:
execvp(...);
/* exec failed and you should exit the
child process here with an error */
exit(errno);
要让父进程知道执行是否失败,应读取子进程的状态:
waitpid(pid, &status, WNOHANG);
然后使用手册页中的WEXITSTATUS(status)
宏:
WEXITSTATUS(status)返回子级的退出状态这个
由状态参数的最低有效8位组成
在对exit(3)或_exit(2)的调用中指定的子级,或作为main()中return语句的参数指定的子级。
注意,最后一条语句的意思是,如果exec
成功并运行该命令,您将获得该命令的main()
函数的退出状态,换句话说您无法可靠地区分失败的exec
和失败的命令之间的区别,因此这取决于这对您是否重要
另一个问题:
如果命令末尾不存在符号“&”,则
父级需要等待子级执行
您需要在程序中的某个点调用子进程上的wait()
,而不管&
如何,以避免使子进程处于僵死状态
注意:当您使用WNOHANG
时,意味着如果没有进程更改其状态,则waitpid()
将立即返回,即它不会阻塞,我假设您知道,否则使用wait()
或调用waitpid()
作为主循环的一部分。对于#2,一个常见的解决方案是在fork()之前打开一个管道,然后在exec之后的子循环中写入它。在父级中,成功读取意味着exec失败;读取失败意味着exec成功,而写入从未发生
// ignoring all errors except from execvp...
int execpipe[2];
pipe(execpipe);
fcntl(execpipe[1], F_SETFD, fcntl(execpipe[1], F_GETFD) | FD_CLOEXEC);
if(fork() == 0)
{
close(execpipe[0]);
execvp(...); // on success, never returns
write(execpipe[1], &errno, sizeof(errno));
// doesn't matter what you exit with
_exit(0);
}
else
{
close(execpipe[1]);
int childErrno;
if(read(execpipe[0], &childErrno, sizeof(childErrno)) == sizeof(childErrno))
{
// exec failed, now we have the child's errno value
// e.g. ENOENT
}
}
这让父级明确地知道exec是否成功,如果失败,errno值作为副产品是什么
如果exec成功,子进程可能仍然会失败,并显示退出代码,使用WEXITSTATUS
宏检查状态也会给出该条件
注意:使用
WNOHANG
标志调用waitpid
是非阻塞的,您可能需要轮询流程,直到返回有效的pid。有史以来最好的问题标题。这里有几个因素可能会影响您的解决方案:您的execvp
将您的流程带入了什么?你有能力编辑吗?在孩子退出之前不知道execvp是否失败可以吗?如果您发布更详细的问题陈述,我们可能会给出更好的建议。如果出现上述故障,您不能从孩子向家长发送信号吗?在这种情况下,您实际上不需要知道execvp是否成功。您需要做的就是决定是否使用WNOHANG
进行waitpid
。如果有&,则使用它。否则,请使用一些结构来监视后台任务。实际上,请查看我给出的答案-它提供了相当不错的代码解决方案。我认为这个问题的困难部分是让父进程知道execvp失败。因为OP不想澄清,我将扮演魔鬼代言人:如果我需要确保孩子在发送信号或其他控制信息之前正确地执行了execvp
ed,因此不能等待它真正退出呢?哦,如果你的waitpid
在execvp
失败之前执行并返回,这将是一个假阳性。@FrankieTheKneeMan但OP的第三个问题是检查它是否完成,这意味着他正在等待子进程并且不想与它说话:)@FrankieTheKneeMan和waitpid
不会返回,除非孩子的状态为changes@Ryan-Callhoun,谢谢,但是阅读会阻止家长,不是吗?如果执行成功,我需要家长不要等待。我编辑了我的帖子来澄清。谢谢@m1o2:注意FD\u CLOEXEC
。当execv*
成功时,子级上的管道关闭。读取将为EOF返回0。如果可用,将pipe2
与O_CLOEXEC
一起使用,而不是pipe
后跟fcntl
。它不仅效率更高,而且还通过打开管道自动设置close-on-exec标志,因此在其他线程也可能运行外部命令的情况下,它可以安全地用于多线程。到目前为止,pipe2
是一个扩展,但它已经被接受包含在下一版本的POSIX中。