【发布时间】:2014-08-07 22:00:44
【问题描述】:
所以我的程序生成了许多子进程来响应某些事件,我正在做类似的事情来跟踪并在程序退出时杀死它们(Perl 语法):
my %children = ();
# this will be called upon exit
sub kill_children {
kill 'INT' => keys %children;
exit;
}
# main code
while(1) {
...
my $child = fork();
if ($child > 0) {
$children{$child} = 1;
} elsif ($child == 0) {
# do child work ...
exit();
} else {
# handle the error
}
}
所以思路如上。但是,那里有一个明显的竞争条件,因为给定的孩子可以在父亲有机会运行并将其 pid 记录在 %children 哈希中之前开始和终止。所以父亲最终可能会认为给定的 pid 属于一个活跃的孩子,即使这个孩子已经终止。
有没有办法以安全的方式完成我想要完成的事情?
编辑:为了更好地跟踪孩子,可以将代码扩展如下(但它也遭受完全相同的竞争条件,所以这就是为什么我一开始没有完全编写它的原因):
my %children = ();
sub reap {
my $child;
while (($child = waitpid(-1, WNOHANG)) > 0) {
#print "collecting dead child $child\n";
delete $children{$child};
}
}
$SIG{CHLD} = \&reap;
# this will be called upon exit
sub kill_children {
local $SIG{CHLD} = 'IGNORE';
kill 'INT' => keys %children;
exit;
}
# main code
while(1) {
...
my $child = fork();
if ($child > 0) {
$children{$child} = 1;
} elsif ($child == 0) {
# do child work ...
exit();
} else {
# handle the error
}
}
即使在这种情况下,%children 的内容也可能无法反映实际活跃的孩子。
编辑 2: 我找到了this question,这几乎是同一个问题。我喜欢那里建议的解决方案。
【问题讨论】:
-
这与 Perl 无关。几乎任何语言都会存在同样的问题。
-
您的示例在 Perl 中,它在没有它的平台上模拟
fork。这可能会对答案产生影响。 -
我可以用 C 编写完全相同的示例,但问题仍然有效。无论如何,我是在 Linux 下运行的。