我使用pipe(),fork(),dup(),execve()生成子进程。
从父级,是否可以安全地等待子级的stdin和stdout关闭(即read()两者都返回0),然后执行waitpid()来收集终止状态?
或者,如果没有关闭stdin和stdout,进程会失败吗? (因此我的程序从未进入waitpid)
澄清一下,我问以下是否安全:
while (child_stdin != -1 && child_stdout != -1) {
poll(...)
if (got_stdout) {
n = read(child_stdout);
if (n >= 0) {
// do something with output
} else if (n == 0) {
child_stdout = -1
}
}
// same for stdin
}
waitpid(child_pid)
或者它可能会发生,孩子会终止,但我永远不会在read()或write()上得到0。
不涉及任何信号,只需轮询() - 。
答案 0 :(得分:6)
如果流程a
产生流程b
,流程b
会产生流程c
(因此c
是a
的孙子), b
可以终止并关闭其stdout文件描述符的副本(可能,b's
stdout是a
正在观看的管道的写入端。)但是{{1}仍然打开该管道,因此c
将从a
获得SIGCHLD,但不会在管道上获得EOF。换句话说,是的,可能会发生孩子终止但父母看不到管道关闭的情况。
此外,b
仍然有管道的写入侧打开是一种常见的编码错误。在这种情况下,a
可以终止并关闭管道写入侧的副本,但父节点永远不会看到管道关闭,因为父节点保持打开状态。
答案 1 :(得分:2)
系统在进程退出时关闭所有文件描述符。可能发生的是,有一些输出存储在缓冲区中,尚未刷新。
如果子进程永远不会终止,那么可能会发生,您的父进程永远等待,永远不会到达waitpid()
。
修改强>
当你的孩子终止时,所有描述符都会关闭,然后你最终会在read()
上得到0(如果出错了,则为-1)。因此,您可能希望更改为:
...
if (n > 0) {
// do something with output
} else if (n <= 0) {
child_stdout = -1
}
您的代码不会因为以下原因而终止:
if (n >= 0) { // n > 0 || n == 0
// ...
} else if (n == 0) {
// Never reached!
}