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

我需要在执行阻塞 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;
};

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

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

【问题讨论】:

    标签: linux perl pipe signals alarm


    【解决方案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)不能更好地解决您的实际问题吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-09
      • 1970-01-01
      • 2014-04-05
      • 2023-03-20
      • 1970-01-01
      • 2012-11-01
      相关资源
      最近更新 更多