我写了两个perl脚本(parent.pl和child.pl),它们的源代码如下:
父.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);
}
孩子.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
or启动system
,所以我使用了另一个自定义信号USR1
。现在效果很好。
==================================================== =======================
上面的修改还是有问题的。分叉的子进程在退出前发送 USR1 信号。可能是父进程之前应该休眠一段时间waitpid
,因为子进程还没有退出。
我现在不手动检索子流程,并设置$SIG{$CHLD} = 'IGNORE'
. 希望子进程退出时能被操作系统找回。