【发布时间】:2015-09-01 16:58:21
【问题描述】:
我正在使用 MCE 做一些事情,它运行良好。我需要观察一个事件的发生,然后派生一个 MCE 进程来处理该事件。这很好用,但是当我认为只有子 MCE 进程应该受到影响时,我遇到了一个问题,即子进程中的错误会杀死父进程。这是一个演示此行为的简短程序。
#!/usr/bin/perl
use strict;
use warnings;
use MCE::Loop;
use MCE::Signal '-setpgrp';
use POSIX "setsid";
$SIG{CHLD} = 'IGNORE';
my $mce_maxWorkers = 2;
my $mce_chunkSize = 1;
my @pids;
my $i = 0;
my $name = shift;
while ($i < 2) {
my $pid = fork();
if (!defined $pid) {
print "Can't fork: $!\n";
}
elsif ($pid == 0) {
#setpgrp(0,0);
(setsid() != -1) || die "Can't start a new session: $!";
MCE::Loop::init {
max_workers => $mce_maxWorkers,
chunk_size => $mce_chunkSize,
on_post_exit => sub {
my ($mce, $e) = @_;
print "$e->{wid}: $e->{pid}: status $e->{status}: $e->{msg}\n";
}
};
my $tail = 'tail -q -f '.$name;
open my $tail_fh, "-|", $tail or die "Can't open tail\n";
mce_loop_f {
my ($mce, $chunk_ref, $chunk_id) = @_;
my $line = ${$chunk_ref}[0];
chomp($line);
print $line."\n";
} $tail_fh;
close $tail_fh;
MCE->shutdown;
exit;
}
else {
print $pid."\n";
$i++;
push(@pids,$pid);
}
}
foreach my $p (@pids) {
waitpid $p, 0;
}
当运行这个程序时,分叉两个子进程,它们尾随一个文件并使用一个具有两个工作进程的 MCE 循环读取其内容。这会产生 7 个进程、1 个父进程、2 个 MCE 管理器和 4 个 MCE 工作者(以及 2 个尾进程)。
使用 setsid,MCE 管理器进程应该与父进程分离。任何导致这些孩子死亡的事情都不应该影响父进程对吗?
这是 ps -efj | 的结果grep 监视器
user1 29001 978 29001 978 0 11:41 pts/2 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
user1 29002 29001 29002 29002 0 11:41 ? 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
user1 29003 29001 29003 29003 0 11:41 ? 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
user1 29004 29002 29002 29002 0 11:41 ? 00:00:00 tail -q -f tmp/monitor1/test1.log
user1 29005 29003 29003 29003 0 11:41 ? 00:00:00 tail -q -f tmp/monitor1/test1.log
user1 29006 29002 29002 29002 0 11:41 ? 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
user1 29007 29002 29002 29002 0 11:41 ? 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
user1 29008 29003 29003 29003 0 11:41 ? 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
user1 29009 29003 29003 29003 0 11:41 ? 00:00:00 /usr/bin/perl ./monitor1_test.pl tmp/monitor1/test1.log
如果我要向上面的 29002 发送 SIGTERM,我希望该进程与 29004、29006 和 29007 一起终止。我还希望进程 29001 和 29003 不受影响。
但是,我看到的是 29001 与 29002 一起死亡,而 29003 仍然存在。在终端上观察到以下错误。
shell $ ./monitor1_test.pl tmp/monitor1/test1.log
29002
29003
test1234
test1234
## monitor1_test.pl: caught signal (INT), exiting
Killed
shell $ MCE::shutdown: method cannot be called while running at /usr/share/perl5/site_perl/MCE/Signal.pm line 371.
END failed--call queue aborted at ./monitor1_test.pl line 371, <$tail_fh> line 1.
为什么其中一个子进程的终止会以这种方式影响父进程?我是否做错了什么或做出了错误的假设,即父母应该度过这个难关?我现在有点烦恼,所以非常感谢任何建议。
平台:Linux 4.0.6 x86_64
Perl:5.22
【问题讨论】:
-
你发送了 SIGTERM,但父级收到了 SIGINT?
-
kill('INT', $_is_MSWin32 ? -$$ : -getpgrp);in MCE::Signal 可能负责。 -
@ikegami 谢谢你是对的。我在 Signal.pm 上进行了攻击,在许多情况下进程组被终止,并且在这些终止中也引用了 $main_proc_id (父 pid)。我确信有一个适当的方法可以解决它,但这看起来是根本原因。谢谢!
-
不会打电话给
setpgrp吗? -
我很早就尝试过(评论仍在上面的脚本中),但问题仍然存在。该问题似乎与 MCE::Signal 将 HUP、INT、QUIT 和 TERM 分配给 \&stop_and_exit 的事实有关。为了获得我正在寻找的功能,我必须在子进程中使用 setpgrp 并在我的脚本中将 $SIG{TERM} 设置回 DEFAULT。这使我可以在不影响父进程组的情况下终止子进程组。
标签: linux perl parallel-processing