stdin / stderr是否保证在进程终止后关闭?

时间:2012-11-01 17:11:47

标签: c posix

我使用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。

不涉及任何信号,只需轮询() - 。

2 个答案:

答案 0 :(得分:6)

如果流程a产生流程b,流程b会产生流程c(因此ca的孙子), 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!
}