IPC :: Run - 检测早产儿出口和封闭管道

时间:2017-06-26 11:40:10

标签: perl fork ipc

我想使用IPC :: Run通过孩子的STDIN,STDOUT和STDERR(启动,泵,完成)与孩子进行交流。它似乎有效。

我想知道如何检测

  • 过早退出孩子(例如由错误引起)
  • 儿童关闭的管道

2 个答案:

答案 0 :(得分:3)

pump针对错误抛出die,或者在所有已完成的活动完成后调用" }时将其消息写入STDERR。 #34;请在ROUTINES部分和pump之前查看。如果孩子退出,第二种情况就会发生。因此,将pump调用封装在eval中,并将警告转换为die以捕获这两种情况

if ($talk_to_child) 
{
    eval {
        local $SIG{__WARN__} = sub { die "pump WARNING: @_" };
        pump $harness;
    };
    if ($@) { 
        print $@;
        $talk_to_child = 0;
    }; 
}
# ... and eval {} for finish()

但是这一点并没有削减它:当父母试图写一个退出它的孩子时会得到一个SIGPIPE,它会直接终止这个过程。当孩子关闭流并且父尝试写时,情况也是如此。因此,还要为SIGPIPE

安装信号处理程序
$SIG{PIPE} = sub { 
    say "$_[0]: $!";
    $talk_to_child = 0;  # global
};

以便父母幸存SIGPIPE。 <{1}}因为eval投掷而仍然需要pump

这些一起照顾我提出的所有测试,实际上就像他们的立场一样。仍然需要处理程序和eval中的一些处理来区分感兴趣的案例(如果需要)。

如果这加起来太多,另一种方法是在每次通话前检查。请参阅this post以获取单行检查(包含在子单元格中):( 1)孩子是否正在运行,使用result,以及(2)&#34; 是否有开放I / O渠道或活动流程&#34;,使用pumpable

我认为你想要两者,并且还要投入SIGPIPE处理程序。这应该涵盖它。

我在这里不能更具体,因为这个问题并没有提供具体细节。

答案 1 :(得分:1)

更新:感谢@zdim提醒我查看SIGPIPE信号。以下是我的答案更新,同时还会检查SIGPIPE

我使用startpumpfinish进行了简单的测试。这是我使用的主要脚本p.pl

use feature qw(say);
use strict;
use warnings;
use IPC::Run;

my $child_in;
my $child_out;
my $child_err;
my $child_name = shift;

my $harness = eval {
    IPC::Run::start [ $child_name ], \$child_in, \$child_out, \$child_err;
};
if ( $@ ) {
    chomp $@;
    die "Caught exception: '$@'";
}
for (1..2) {
    $child_in = "Joe$_\n";
    say "Parent sleeping for 1 second..";
    sleep 1;
    eval {
        local $SIG{PIPE} = sub { 
            die "Parent received SIGPIPE. "
              . "Child is either dead or has closed its input pipe\n";
        };
        say "Sending data to child..";
        my $result = $harness->pump;
        say "IPC::Run::pump() returned: ", $result ? "TRUE" : "FALSE";
    };
    if ( $@ ) {
        chomp $@;
        say "IPC::Run::pump() failed: '$@'";
        last;
    }
    say "\$child_in = '$child_in'";
    say "\$child_out = '$child_out'";
}
say "Finishing harness..";
my $res = eval {
    local $SIG{PIPE} = sub { 
        die "Parent received SIGPIPE. "
          . "Child is either dead or has closed its input pipe\n";
    };
    $harness->finish;
};
if ( $@ ) {
    chomp $@;
    die "IPC::Run::finish() failed: '$@'\n";
}
printf "IPC::Run::finish() returned: '%s'\n", $res ? "TRUE" : "FALSE";
chomp $child_out;
say "STDOUT from child: '$child_out'";
chomp $child_err;
say "STDERR from child: '$child_err'";
say "Child returned exit code: ", $harness->result;
say "Parent exited normally.."

我使用了三种不同的子脚本:

<强> child.pl

#! /usr/bin/env perl    
use feature qw(say);
use strict;
use warnings;

my $reply = <STDIN>;
chomp $reply;
say "Hello $reply";
my $reply2 = <STDIN>;
chomp $reply2;
say "Got second reply: $reply2";
exit 0;

并输出:

$ p.pl child.pl
Parent sleeping for 1 second..
Sending data to child..
IPC::Run::pump() returned: TRUE
$child_in = ''
$child_out = ''
Parent sleeping for 1 second..
Sending data to child..
IPC::Run::pump() returned: TRUE
$child_in = ''
$child_out = ''
Finishing harness..
IPC::Run::finish() returned: 'TRUE'
STDOUT from child: 'Hello Joe1
Got second reply: Joe2'
STDERR from child: ''
Child returned exit code: 
Parent exited normally..

<强> child2.pl

#! /usr/bin/env perl
use feature qw(say);
use strict;
use warnings;

my $reply = <STDIN>;
chomp $reply;
say "Hello $reply";
die "Child exception\n";

并输出:

$ p.pl child2.pl
Parent sleeping for 1 second..
Sending data to child..
IPC::Run::pump() returned: TRUE
$child_in = ''
$child_out = ''
Parent sleeping for 1 second..
Sending data to child..
IPC::Run::pump() failed: 'Parent received SIGPIPE. Child is either dead or has closed its input pipe'
Finishing harness..
IPC::Run::finish() failed: 'Parent received SIGPIPE. Child is either dead or has closed its input pipe'

<强> child3.pl

#! /usr/bin/env perl
use strict;
use warnings;

close \*STDIN;
close \*STDOUT;
close \*STDERR;
sleep 5;
exit 2;

并输出:

$ p.pl child3.pl 
Parent sleeping for 1 second..
Sending data to child..
IPC::Run::pump() failed: 'ack Parent received SIGPIPE. Child is either dead or has closed its input pipe'
Finishing harness..
IPC::Run::finish() failed: 'Parent received SIGPIPE. Child is either dead or has closed its input pipe'

因此,对于这些测试,似乎SIGPIPE信号可用于检查子项是否处于活动状态或已关闭其输入管道。请注意,如果您在孩子退出后尝试呼叫pump(),则孩子的上一个输出会丢失,请参阅child2.pl示例。