2017-06-26 21 views

回答

2

pump抛出错误的一种die,或者将其消息写入STDERR全部利用,活动后调用已完成”。请参阅ROUTINES部分和pump本身。如果孩子退出,第二种情况可能会出现。所以包裹pump呼叫eval,并转换警告die赶上这两种情况下

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

但仅有这将不会削减它:当父母试图写入到该退出它得到一个SIGPIPE一个孩子,彻底终止了这一过程。当小孩关闭流和父母尝试写入时也是如此。所以也为它安装一个信号处理程序

$SIG{PIPE} = sub { 
    say "$_[0]: $!"; 
    $talk_to_child = 0; # global 
}; 

这样父母就能够幸存SIGPIPE。仍然需要,因为pump也会抛出。

这些在一起照顾我想出的所有测试,实际上就像它们站立一样。尽管如此,需要处理程序和eval中的一些处理来区分感兴趣的案例。

如果这加起来太多,另一种方法是在每次调用之前检查。请参阅this post以进行单行检查(包裹在子目录中):(1)子女是否正在使用result,以及(2)“是否有开放式I/O通道或活动进程”,使用pumpable

我认为你想要两个,并且还要扔SIGPIPE处理程序。这应该包括它。

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

+0

'SIGPIPE'很好的捕获。我认为那就是我所缺少的:) –

+0

@HåkonHægland正确的说,'SIGPIPE'是表演的终结者。但这仍然很复杂。在每次调用之前使用'result'和'pumpable'(加上'SIGPIPE'处理程序)组合来检查可能会更简单。 – zdim

+0

@ AndrzejA.Filip我用直接使用'result' +'pumpable'(+'SIGPIPE'处理程序)进行检查的评论更新了答案。我还编辑了一些准确的评论。我在我的测试中证实,答案中的主要方法确实可以处理所有情况,实际上就像现在这样。让我们知道它是如何为你工作的。 @Håkon的答案也得到了更新。 – zdim

1

更新关闭:感谢@zdim为提醒我检查SIGPIPE信号。这里是我的答案更新,也检查SIGPIPE

我做了一个简单的测试,使用start,0 pumpfinish。这里是主要的脚本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 ([email protected]) { 
    chomp [email protected]; 
    die "Caught exception: '[email protected]'"; 
} 
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 ([email protected]) { 
     chomp [email protected]; 
     say "IPC::Run::pump() failed: '[email protected]'"; 
     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 ([email protected]) { 
    chomp [email protected]; 
    die "IPC::Run::finish() failed: '[email protected]'\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' 

所以对于这些工商业污水附加费ts,似乎SIGPIPE信号可用于检查孩子是否活着或已关闭其输入管道。请注意,如果您在孩子退出后尝试致电pump(),则以前的孩子输出将丢失,请参阅child2.pl示例。

+0

我感兴趣的是**长**运行的孩子与大量的“命令 - 响应”序列的情况。我想避免将命令按压到封闭STDIN的孩子身上或者从封闭STDOUT的孩子那里抽取回复。 – AnFi