Perl open2()和SIGCHLD,死锁?

时间:2016-07-16 12:41:58

标签: perl pipe signals freebsd perl5

从FreeBSD上的Perl脚本中,我用IPC::Open2::open2()打开几个子进程,向每个进程传递它的参数"通过它的stdin(可能我应该在此之后关闭stdin)并且我也这样做:

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;

现在的问题是:像这样的代码中的某些内容会导致死锁吗?我更喜欢读取孩子的输出而不是它到达时,但是当它终止时读取整个输出;可能会引起问题吗?

"参数"我通过stdin传给一个孩子可能是一根长串。我将使用子stdin的FD通过一个print运算符传递整个字符串。它可以在将参数写入脚本的过程中阻塞吗?

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

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

更具体的问题:可以写入PIPE(双方打开但不会被关闭)阻止(如果对方不读它)?

2 个答案:

答案 0 :(得分:1)

  

可以写入PIPE(双方打开但不会关闭)阻止(如果对方没有读取它)?

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

例如,孩子可能会发生以下情况:

  1. 写入STDOUT
  2. 写入STDOUT
  3. ...
  4. 写入STDOUT
  5. 尝试写入STDOUT,但管道已满,因此它会阻塞,直到管道被清空一些。
  6. 如果发生这种情况,孩子将无限期地被阻止(因此永远不会退出),因为父母在孩子退出之前不会从管道中读取。这在技术上不是deadlock,因为父母仍然可以随心所欲地做任何事情,但这肯定是个问题。

    注意:如果子句使句柄无阻塞,则写入将失败而不是阻塞。

答案 1 :(得分:0)

来自http://man7.org/linux/man-pages/man7/pipe.7.html(不是FreeBSD,但我认为这无所谓;毕竟我们可能会改变我们的操作系统。)

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

因此,子进程可能会“挂起”尝试向我们写入数据,并且当它终止时我们可以无限期地等待它。