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

Posted

技术标签:

【中文标题】Perl:关闭信号处理程序中的子进程管道挂起?【英文标题】:Perl: closing subprocess pipe in signal handler hangs? 【发布时间】:2016-01-25 05:27:37 【问题描述】:

我需要在执行阻塞 io 的脚本上超时。 令人惊讶的是,如果子进程有一个打开的管道,exit 就会挂起:

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

$SIGALRM = sub

    print "trying to exit...\n";
    exit 0;     # Hangs with above open() call
;
alarm 1;

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

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

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

$SIGALRM = sub

    print "trying to close...\n";
    close(IN);            # Hangs ...
    print "ok\n";
    exit 0;
;

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

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

【问题讨论】:

【参考方案1】:

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

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

close $foo;     # <--- will block

解决此问题的一种方法是通过open 捕获子进程ID,然后通过kill 捕获该子进程:

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

say "subprocess=$subprocess";

kill 'KILL', $subprocess;

close $foo;     # <--- happy now

【讨论】:

当然你说的很对,傻我!令人困惑的部分是早期的exit 确实有效,但这只是因为它创建了一个竞争条件(孩子还没有准备好)。谢谢!【参考方案2】:

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

【讨论】:

以上是关于Perl:关闭信号处理程序中的子进程管道挂起?的主要内容,如果未能解决你的问题,请参考以下文章

perl 进程之间的 perl Win32 信号处理

持久的子进程管道 - 没有读取标准输出

Perl:当子/管道的文件句柄被别名时,关闭子进程失败

进程挂起,PIPE 被阻塞

linux虚拟内存附加/分离信号

8种进程间通信方式