我正在运行一个IRC Bot(Bot::BasicBot),它有两个运行File::Tail的子进程但是在退出时它们不会终止。所以我在退出前使用Proc::ProcessTable像这样杀死他们:
my $parent=$$;
my $proc_table=Proc::ProcessTable->new();
for my $proc (@{$proc_table->table()}) {
kill(15, $proc->pid) if ($proc->ppid == $parent);
}
它有效,但我收到了这个警告:
14045: !!! Child process PID:14047 reaped: 14045: !!! Child process PID:14048 reaped: 14045: !!! Your program may not be using sig_child() to reap processes. 14045: !!! In extreme cases, your program can force a system reboot 14045: !!! if this resource leakage is not corrected.
我还能做些什么来杀死子进程?分叉流程是使用forkit中的Bot::BasicBot方法创建的。
示例脚本:
package main;
my $bot = SOMEBOT->new ( server => 'irc.dal.net', channels => ['#anemptychannel'] );
$SIG{'INT'} = 'Handler';
$SIG{'TERM'} = 'Handler';
sub Handler {
$bot->_stop('Leaving.');
}
$bot->run;
package SOMEBOT;
use base qw(Bot::BasicBot);
use File::Tail;
use Proc::ProcessTable;
sub irc_error_state { die if $_[10] =~ /Leaving\./; }
sub help { return; }
sub stop_state {
my $parent=$$;
my $proc_table=Proc::ProcessTable->new();
for my $proc (@{$proc_table->table()}) {
kill(15, $proc->pid) if ($proc->ppid == $parent);
}
die;
}
sub connected {
my $self = shift;
$self->forkit (
run => \&announcer,
body => '/home/somebody/somefile.txt',
channel => '#anemptychannel',
) unless $self->{log1};
$self->{log1} = 1;
$self->forkit (
run => \&announcer,
body => '/home/somebody/anotherfile.txt',
channel => '#anemptychannel',
) unless $self->{log2};
$self->{log2} = 1;
}
sub announcer {
my $announcefile = shift;
my $file=File::Tail->new(name => $announcefile, maxinterval=>5, adjustafter=>7);
while (defined(my $line=$file->read)) { chomp $line; print "$line\n"; }
}
答案 0 :(得分:1)
我不熟悉你提到的任何模块,但是当我在过去编写过Perl程序时,它通常足以将这一行放在主要的父进程中:
$SIG{CHLD} = sub { wait };
这样,当子进程退出并且父进程获得SIGCHLD信号时,它会自动使用wait
重新获得子进程。
答案 1 :(得分:1)
从版本0.82开始,Bot::BasicBot
将在退出时终止未完成的子进程(由forkit()
创建)。
答案 2 :(得分:1)
我正在挖掘一个旧帖子,但我正在寻找这个问题的答案,Google搜索将此作为最佳结果。所以,如果其他人偶然发现了这一点,我就是这样做的。
在分叉之前,设置pipe
以便您的分叉进程可以进行通信:
pipe PARENTRECEIVE,CHILDSEND;
分叉您的流程并让孩子非常地向父母发送新的流程ID。然后,当您认为孩子被挂起时(通过计时器或SIG),您可以杀死子进程:
my $pid = fork();
if ($pid eq 0) {
#child block
my $cid = $$;
print CHILDSEND "$cid\n";
<do child stuff which might hang>
}
else {
#parent block
my $child_id = <PARENTRECEIVE>;
chomp $child_id;
<do parent stuff>
<if you think child is hung> {
kill 1, $child_id;
}
}
有时我们的网络服务器会挂起,所以我用它来检查它是否仍然在合理的时间内响应HTTP GET请求。如果孩子在父母的计时器启动之前没有完成抓取URL,它会发出一封电子邮件提醒,说明事情已经结束。
答案 3 :(得分:0)
我会关注您的子进程未正确终止的原因。在“正常”情况下,父母不应该做任何事情(如果您关心结果,可以致电waitpid
,或者在完成之前停止处理)。
这还不是一个很好的答案 - 你可能不得不在孩子们中粘贴一些代码。但是一些建议 - 从手动调用fork
的简单程序开始,而不是依靠CPAN模块为您完成。了解系统如何处理多个进程非常重要。然后,当你得到它时,你可以利用一些框架为你处理很多过程。
如果你最近没有这样做,你应该阅读perldoc perlfork,并尝试一些例子。