Простой пример open3 не работает
Я пытаюсь сделать мастер Perl-скрипт, вызывающий дочерний Perl-скрипт и взаимодействующий через канал.
Я написал этот код для мастера:
#!/usr/bin/env perl
use strict;
use warnings;
use IPC::Open3;
my @children;
for my $i ( 0 .. 4 ) {
print "Master: " . $i . ", I summon you\n";
$children[$i] = {};
$children[$i]->{'pid'} = open3( my $CH_IN, my $CH_OUT, my $CH_ERR, 'perl child.pl -i ' . $i );
$children[$i]->{'_STDIN'} = $CH_IN;
$children[$i]->{'_STDOUT'} = $CH_OUT;
$children[$i]->{'_STDERR'} = $CH_ERR;
my $line = readline $children[$i]->{'_STDOUT'};
print $line ;
}
print "Master: Go fetch me the sacred crown\n";
for my $i ( 0 .. 4 ) {
$children[$i]->{'_STDIN'}->write("fetch the sacred crown\n");
my $line = readline $children[$i]->{'_STDIN'};
print $line ;
}
print "Master: Thanks. Now die!!!\n";
for my $i ( 0 .. 4 ) {
$children[$i]->{'_STDIN'}->write("die !!\n");
my $line = readline $children[$i]->{'_STDIN'};
print $line ;
}
И этот для ребенка:
#!/usr/bin/env perl
use Getopt::Long ;
my $cmdline_id ;
GetOptions ('i=s' => \$cmdline_id) ;
my $id = $cmdline_id ;
exit 1 if !defined $id ;
print "I am $id, and I am awaken\n" ;
while(<STDIN>) {
print STDOUT $id . ': Master ask me to ' . $_ ;
if ($_ =~ /exit/oi) {
exit 0 ;
}
}
Но когда я запускал Учителя, он просто висел, читая ответ ребенка.
Есть идеи о том, что я сделал не так и почему?
2 ответа
Решение
Сказать $|=1
в начале дочернего процесса, чтобы дочерний процесс мог печатать, не дожидаясь заполнения выходного буфера.
Как примечание: передача undef для третьего аргумента (как и вы) не делает то, что вы хотите. Вам нужно инициализировать переменную, используя Symbol gensym
,
use Symbol qw( gensym );
my %child;
$child{pid} = open3(
$child{'_STDIN' } = gensym,
$child{'_STDOUT'} = gensym,
$child{'_STDERR'} = gensym,
'perl', 'child.pl', '-i' => $i
);
$children[$i] = \%child;