Я написал два сценария perl (parent.pl и child.pl), и их исходные коды следующие:
parent.pl:
# file parent.pl
$SIG{CHLD} = sub {
while(waitpid(-1, WNOHANG) > 0) {
print "child process exit\n";
}
};
my $pid = fork();
if($pid == 0) {
system("perl child.pl");
exit;
}
while(1) {
open my $fh, "date |";
while(<$fh>) {
print "parent: ".$_;
}
close $fh;
sleep(2);
}
child.pl
#file child.pl
while(1) {
open my $fh, "date |";
while(<$fh>) {
print " child: ".$_;
}
close $fh;
sleep(2);
}
Я хочу, чтобы родительский процесс и разветвленный подпроцесс поочередно выводили текущую дату. Но когда я запускаю perl parent.pl
, результат будет таким:
$ perl parent.pl
parent: Mon Jan 21 14:53:36 CST 2013
child: Mon Jan 21 14:53:36 CST 2013
child: Mon Jan 21 14:53:38 CST 2013
child: Mon Jan 21 14:53:40 CST 2013
child: Mon Jan 21 14:53:42 CST 2013
child: Mon Jan 21 14:53:44 CST 2013
Похоже, что родительский процесс был заблокирован при открытии трубы.
Но если я уберу следующую операцию для сигнала CHLD.
$SIG{CHLD} = sub {
while(waitpid(-1, WNOHANG) > 0) {
print "child process exit\n";
}
};
И снова запустить. Вроде нормально.
$ perl parent.pl
parent: Mon Jan 21 14:57:57 CST 2013
child: Mon Jan 21 14:57:57 CST 2013
parent: Mon Jan 21 14:57:59 CST 2013
child: Mon Jan 21 14:57:59 CST 2013
parent: Mon Jan 21 14:58:01 CST 2013
child: Mon Jan 21 14:58:01 CST 2013
Но я все еще чувствую недоумение. Почему родительский процесс был заблокирован, когда я пытался открыть канал?
Я не думаю, что удаление функции SIG {CHLD} - хорошая идея, потому что зомби-процессы должны быть восстановлены.
Кто-нибудь может мне помочь? Большое спасибо!
==================================================================
Спасибо @Borodin за помощь в решении моей головоломки. И я попытался изменить parent.pl
следующим образом:
my $main_pid = $$;
$SIG{USR1} = sub {
#sleep(1);
while(waitpid(-1, WNOHANG) > 0) {
print "child process exit\n";
}
};
my $pid = fork();
if($pid == 0) {
$SIG{USR1} = 'IGNORE';
system("perl child.pl");
kill USR1, $main_pid;
exit;
}
while(1) {
open my $fh, "date |";
while(<$fh>) {
print "parent: ".$_;
}
close $fh;
sleep(2);
}
Поскольку сигнал CHLD
может быть запущен open
или system
, я использовал другой настроенный сигнал USR1
. И сейчас это хорошо работает.
========================================================================
У вышеуказанной модификации все еще есть проблемы. Разветвленный подпроцесс отправляет единичный номер USR1 перед завершением. Возможно, родительский процесс должен некоторое время засыпать до waitpid
, потому что подпроцесс еще не завершился.
Я сейчас не извлекаю подпроцесс вручную, а устанавливаю $SIG{$CHLD} = 'IGNORE'
. Надеюсь, что подпроцесс может быть восстановлен операционной системой при выходе.