6

我正在运行一个 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:!!!子进程 PID:14047 收割:
14045:!!!子进程 PID:14048 收割:
14045:!!!您的程序可能没有使用 sig_child() 来获取进程。
14045:!!!在极端情况下,您的程序可以强制系统重启
14045:!!!如果不纠正这种资源泄漏。

我还能做些什么来杀死子进程?分叉进程是使用Bot::BasicBot中的forkit方法创建的。

示例脚本:

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"; }
}
4

4 回答 4

1

从 0.82 版开始,将在退出时终止Bot::BasicBot未完成的子进程(由 创建)。forkit()

于 2011-12-14T13:21:19.630 回答
1

我不熟悉您提到的任何模块,但是当我过去编写分叉 Perl 程序时,通常将这一行放在主父进程中就足够了:

$SIG{CHLD} = sub { wait };

这样,当子进程退出并且父进程收到 SIGCHLD 信号时,它会自动使用wait.

于 2010-03-21T17:43:41.217 回答
1

我正在挖掘一篇旧帖子,但我一直在寻找这个问题的答案,而谷歌搜索将其列为最高结果。所以,如果其他人偶然发现了这个,我就是这样做的。

在分叉之前,设置一个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;
  }
}

有时我们的 Web 服务器会挂起,因此我使用它来检查它是否仍在合理的时间内响应 HTTP GET 请求。如果孩子在父母的计时器到时之前没有完成抓取 URL,它会发送一封电子邮件警报,告知有什么事情发生了。

于 2013-03-05T15:44:12.030 回答
0

我会担心为什么您的子进程没有正确终止。在“正常”情况下,父母不应该做任何事情(waitpid如果您关心结果,可能会打电话,或者在完成之前暂停处理)。

这还不是一个真正的答案——您可能必须将一些代码粘贴到孩子中。但有一点建议——从手动调用的简单程序开始fork,而不是依赖 CPAN 模块为您完成。了解系统如何处理多个进程非常重要。然后,当你得到它时,你可以利用一些框架来为你处理很多流程。

如果您最近没有阅读perldoc perlfork ,您可能还应该阅读并尝试一些示例。

于 2010-03-21T16:51:39.563 回答