2017-06-26 27 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