Perl:关闭信号处理程序中的子进程管道挂起?

Perl: closing subprocess pipe in signal handler hangs?

我需要在执行阻塞 io 的脚本上超时。
令人惊讶的是,如果存在通往子进程的开放管道,结果 exit 会挂起:

#!/usr/bin/perl                                                                                             
(-f "foo") || die "file foo doesn't exist";
open(IN, "tail -f foo |");

$SIG{ALRM} = sub
{
    print "trying to exit...\n";
    exit 0;     # Hangs with above open() call
};
alarm 1;

while (1)
{   
    sleep 5;   # Do stuff ...
}

没有 open 调用它就可以工作,不幸的是删除它不是一个选项,在这种情况下脚本需要它。

看起来 exit 正在尝试关闭文件句柄,这就是挂起的内容:

$SIG{ALRM} = sub
{
    print "trying to close...\n";
    close(IN);            # Hangs ...
    print "ok\n";
    exit 0;
};

我想从信号处理程序中获取子进程并不太高兴...

有人知道解决这个问题的好方法吗?

像手册页建议的那样直接使用 POSIX::_exit() 似乎可以解决这个特定问题。但这有点像 A-B 问题。您确定使用比普通管道更复杂的处理子流程的方法不会更好地解决您的实际问题,例如 IPC::Run?

信号处理程序是红色鲱鱼,close 无论如何都会阻塞:

open my $foo, "tail -f foo |" or die "Can't open process: $!";

close $foo;     # <--- will block

解决此问题的一种方法是通过 open and then kill 子进程捕获子进程 ID:

my $subprocess = open my $foo, "tail -f foo |" or die "Can't open process: $!";

say "subprocess=$subprocess";

kill 'KILL', $subprocess;

close $foo;     # <--- happy now