Perl open2() 和 SIGCHLD,死锁?

Perl open2() together with SIGCHLD, deadlock?

我从 FreeBSD 上的一个 Perl 脚本打开了几个 child 进程 IPC::Open2::open2(),通过它的标准输入将它的 "parameters" 传递给每个进程(可能我应该在这之后关闭标准输入)和我也是:

sub handle_SIGCHLD {
  for(;;) {
    my $kid = waitpid(-1, WNOHANG);
    break if $kid == 0;
    my $KidOutputFD = ...; # I stored the kid's output pipe FD earlier in the program
    my $KidOutput = read_file($KidOutputFD); # use File::Slurp
    # process $KidOutput
  }
}}

$SIG{'CHLD'} = \&handle_SIGCHLD;

现在的问题是:像这样的代码会导致死锁吗?我更喜欢读取 kid 的输出,而不是在它到达时读取,而是在它终止时读取整个输出;会不会出问题?

另外,我通过 stdin 传递给孩子的 "parameters" 可能是一个长字符串。我将通过一个带有 child 标准输入 FD 的 print 运算符传递整个字符串。它可以在将参数写入脚本的过程中阻塞吗?

我还应该做些什么来确保没有死锁?也许我应该处理 SIGPIPE? (我不想这样做,通过 child 过程将输入字符串简单地转换为输出字符串需要做太多工作。有更简单的方法吗?)

另请注意,我跨越了多个 child 进程。有时我在进程终止时等待,有时我用 SIGTERM 杀死一个 child 进程。


更具体的问题:写一个PIPE(两边都打开,不会关闭)会不会阻塞(如果另一边不读)?

来自 http://man7.org/linux/man-pages/man7/pipe.7.html(不是 FreeBSD,但我认为这无关紧要;毕竟我们有可能改变我们的 OS)。

管道容量 管道的容量是有限的。如果管道已满,则 write(2) 将阻塞或失败,具体取决于是否设置了 O_NONBLOCK 标志(见下文)。

因此,子进程可能 "hang" 尝试向我们写入数据,作为一个 dealock,我们可以在它终止时无限等待。

May writing to a PIPE (which is opened at both sides and is not going to be closed) block (if the other side does not read it)?

绝对是。管道的容量是有限的,如果管道已满,写入管道将会阻塞。

例如,在 child 中可能会发生以下情况:

  1. 写入 STDOUT
  2. 写入 STDOUT
  3. ...
  4. 写入 STDOUT
  5. 尝试写入 STDOUT,但管道已满,因此它会阻塞,直到管道清空一些。

如果发生这种情况,child 将无限期地保持阻塞状态(因此永远不会退出),因为 parent 在 child 退出之前不会从管道中读取数据。这在技术上不是 deadlock,因为 parent 仍然可以自由地做任何它想做的事,但这绝对是一个问题。

注意:如果child使句柄non-blocking,写入将失败而不是阻塞。