子进程是否保持管道打开?

子进程是否保持管道打开?

我试图了解在管道中运行时启动子进程的程序的行为。

这个 bash 程序 fork.sh 立即打印并返回:

(sleep 1) &
echo 'here'

但是当连接到管道时,读取端似乎等待睡眠完成。

$ time bash fork.sh | wc
       1       1       5

real    0m1.014s

我也在 Ruby 中尝试过此操作,并进行了一些额外的调用来尝试防止睡眠阻塞:

Process.detach(fork { sleep 1 })
puts 'here'
fork {
  sleep 1
  Process.daemon
}
puts 'here'

但他们的行为是一样的。

我想知道是什么原因导致这个问题(就 Unix、文件描述符等而言),以及是否有办法重写其中任何一个,以便管道在一秒钟内返回。


编辑:下面的答案帮助我注意到 Ruby 示例的问题:调用daemon()必须首先进行。我原以为它以某种方式应用于整个过程。

答案1

  1. 子进程从其父进程继承所有文件描述符。
  2. 执行命令时(就像您sleep这里假设您的 shell 没有内置命令一样),只有标有执行时关闭标志已关闭,但 shell 从未在 stdout (fd 1) 上设置该标志。
  3. 管道读者仅当以下情况时才会得到 EOF全部指向其写入端的文件描述符已被关闭。
time bash fork.sh | wc

您应该让您的sleep进程(从 开始fork.sh)放弃其标准输出,该输出指向wc正在读取的管道的写入端;在fork.sh

(sleep 1 >/dev/null) &
echo 'here'

在这种情况下sleep .. >&-(关闭标准输出,而不将其重定向到其他地方)也可以工作,但我一般不建议这样做,因为如果进程随后打开一些文件,返回的文件描述符将为 1 = 标准输出,这可能会中断假设并触发错误。

相关内容