Perl 5.8:当使用SIGCHLD时,可以从反引号中获取任何返回码

时间:2014-11-12 23:21:20

标签: linux perl

当在Perl中使用CHLD信号处理程序时,即使使用系统和反引号也会发送CHLD信号。但对于系统和反引号子进程,wait和waitpid似乎都没有设置$?在SuSE 11 linux上的信号处理程序中。当CHLD信号处理程序处于活动状态时,是否有任何方式来确定反引号命令的返回码?

为什么我要这个?因为我想fork(?)并启动一个中等长度命令,然后调用一个perl包,需要很长时间来产生一个答案(并用反引号执行外部命令并检查它们的返回代码是否为$?),并知道何时我的命令已经完成,所以我可以采取行动,例如开始第二个命令。 (关于如何在不使用SIGCHLD的情况下完成此操作的建议也是受欢迎的。)但是由于信号处理程序会破坏反引号$?值,该包失败。

示例:

use warnings;
use strict;
use POSIX ":sys_wait_h";

sub reaper {
    my $signame = shift @_;
    while (1) {
       my $pid = waitpid(-1, WNOHANG);
       last if $pid <= 0;
       my $rc = $?;
       print "wait()=$pid, rc=$rc\n";
    }
}

$SIG{CHLD} = \&reaper;

# system can be made to work by not using $?, instead using system return value
my $rc = system("echo hello 1");
print "hello \$?=$?\n";
print "hello rc=$rc\n";

# But backticks, for when you need the output, cannot be made to work??
my @IO = `echo hello 2`;
print "hello \$?=$?\n";

exit 0;

在我尝试访问它的所有地方产生-1返回代码:

hello 1
wait()=-1, rc=-1
hello $?=-1
hello rc=0
wait()=-1, rc=-1
hello $?=-1

所以我找不到任何地方可以访问反引号返回值。

2 个答案:

答案 0 :(得分:1)

同样的问题一直困扰着我几天。我相信根据你的反引号在哪里需要2个解决方案。

如果您在子代码中有反对功能:

解决方案是将下面的行放在子fork中。我认为你上面的陈述“如果我完全关闭反引号周围的CHLD处理程序,那么如果孩子结束我可能不会得到信号”是不正确的。当孩子退出时,您仍然会在父母中获得回调,因为该信号仅在孩子内部被禁用。因此,当孩子退出时,父母仍然会收到信号。当孩子的孩子(反叛部分)退出时,孩子才会收到信号。

local $SIG{'CHLD'} = 'DEFAULT'

我不是Perl专家,我读过你应该将CHLD信号设置为字符串'IGNORE'但这在我的情况下不起作用。从表面上看,我认为这可能导致了这个问题。彻底解决这个问题似乎也解决了我认为与将其设置为DEFAULT相同的问题。

如果您在父代码中有反引号:

将此行添加到您的收割者功能: local ($!, $?);

当你的反引号中的代码完成而收割者设置$?时,正在调用收割机。通过赚$?本地它没有设置全局$?。

答案 1 :(得分:0)

所以,基于MikeKull的回答,这是一个工作示例,其中fork'd的孩子使用反引号并仍然获得正确的返回代码。这个例子更好地代表了我在做什么,而原始的例子没有使用分叉,也无法传达整个问题。

use warnings;
use strict;
use POSIX ":sys_wait_h";

# simple child which returns code 5
open F, ">", "exit5.sh" or die "$!";
print F<<EOF;
#!/bin/bash
echo exit5 pid=\$\$
exit 5
EOF
close F;

sub reaper
{
    my $signame = shift @_;
    while (1)
    {
        my $pid = waitpid(-1, WNOHANG);
        print "no child waiting\n" if $pid < 0;
        last if $pid <= 0;
        my $rc = $? >> 8;
        print "wait()=$pid, rc=$rc\n";
    }
}

$SIG{CHLD} = \&reaper;

if (!fork)
{
    print "child pid=$$\n";
  { local $SIG{CHLD} = 'DEFAULT'; print `./exit5.sh`; }
    print "\$?=" . ($? >> 8) . "\n";
    exit 3;
}

# sig CHLD will interrupt sleep, so do multiple
sleep 2;sleep 2;sleep 2;

exit 0;

输出结果为:

child pid=32307
exit5 pid=32308
$?=5
wait()=32307, rc=3
no child waiting

因此,当父母的收割者在打电话给孩子之前被禁用时,孩子收到了预期的返回码5,但正如ikegami所示,当孩子退出时,父母仍然会得到CHLD信号和正确的返回码。