【问题标题】:Process hanging -SIGALRM not delivered- Perl进程挂起-SIGALRM 未交付-Perl
【发布时间】:2013-08-21 13:27:24
【问题描述】:

我有一个使用 OPEN 和管道执行的命令,我想设置 10 秒的超时时间,如果执行时间超过此时间,则子进程中止。但是,我的代码只会导致程序挂起 - 为什么我的 ALARM 没有正确传递?

my $pid = 0;
my $cmd = "someCommand";
print "Running Command # $num";
eval {
    local $SIG{ALRM} = sub {                    
        print "alarm \n";
        kill 9, $pid;
    };              
    alarm 10;
    pid = open(my $fh, "$cmd|");
    alarm 0;
};
if($@) {
    die unless $@ eq "alarm \n";
} else {
    print $_ while(<$fh>);
}

编辑:

所以从下面的答案来看,这就是我所拥有的:

my $pid = open(my $fh, qq(perl -e 'alarm 10; exec \@ARGV; die "exec: $!\n" ' $cmd |));
print $_ while(<$fh>);

但是当闹钟超时时这个打印 ALARM CLOCK 到控制台......而我没有在代码中的任何地方指定这个......我怎样才能摆脱这个,我应该把自定义闹钟事件处理程序放在哪里?

谢谢!

【问题讨论】:

    标签: perl


    【解决方案1】:

    我想设置一个 10 秒的超时时间,如果执行时间超过这个时间,子进程就会中止

    另一种方法是在子流程本身上设置警报,使用您已经拥有的方便的脚本语言:

    my $cmd = "someCommand";
    my $pid = open(my $child_stdout, '-|',
       'perl', '-e', 'alarm 10; exec @ARGV; die "exec: $!"', $cmd);
    ...
    

    您的子进程最初将是 perl(好吧,shell 然后是 perl),它将对其自身设置警报,然后执行(将其自身替换为)$someCommand。然而,待处理的警报是inherited across exec()s

    【讨论】:

    • 谢谢。我可以做些什么来重置每个执行人员的警报吗?我将如何处理发出警报的情况?比如,我应该把处理代码放在哪里?
    • 谢谢,@ikegami。我拒绝这样做,因为我怀疑“someCommand”实际上可能是“someCommand --with=blank-separated args”。
    • @user6561,每个 exec() 都会重置警报 。它对于每个生成的进程都是独一无二的。关于错误处理,您会在生成的进程终止后注意到$? 中的信号死亡。在我的系统上,$? &amp; 127 == 14(14 是 SIGALRM)。有关更多详细信息,请参阅system 的文档。
    • 好的,我明白了,非常感谢!还有 2 个问题: 1. 在 Perldoc 上,它说 exec 不返回..所以在这种情况下,我们如何在 exec 上方设置警报并等待它?以及 2. 当警报超时时,被执行的进程会死掉吗?
    • @user6561,你的 perl 脚本会生成一个子进程。那个孩子最初是一个新的 perl 进程。这第二个 perl 进程为自己设置了一个警报。然后它将其进程映像 (exec()) 替换为您的“someCommand”。这个新的进程映像是一个不同的程序,但保留了现已消失的第二个 perl 进程的一些属性:PID、父进程(也就是说,我们仍然是您的顶级 perl 脚本的子进程)、进程组、会话、权限(通常)、未决内核警报等。
    【解决方案2】:

    您的代码所做的只是在 open 调用上设置 10 秒超时,而不是在整个外部程序上。您希望将与外部命令的其余交互带入 eval 块:

    eval {
        local $SIG{ALRM} = sub {                    
            print "alarm \n";
            kill 9, $pid;
        };              
        alarm 10;
        $pid = open(my $fh, "$cmd|");
        print while <$fh>;
        close $fh;
        alarm 0;
    };
    if($@) {
        die unless $@ eq "alarm \n";
    }
    

    【讨论】:

    • 这会传递 ALARM CLOCK 信号,但会在发出警报信号时终止整个程序...你知道为什么会这样吗?
    • 呃,...,不。它是否在您的 if($@){...} 块中执行 die 函数? $@的内容是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    • 2011-01-15
    相关资源
    最近更新 更多