在退出之前终止 Perl 中的子进程的正确方法是什么?

发布于 2024-08-25 18:55:00 字数 2432 浏览 7 评论 0 原文

我正在运行一个 IRC 机器人 (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 方法创建的://search.cpan.org/perldoc/Bot::BasicBot" rel="noreferrer">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"; }
}

I'm running an IRC Bot (Bot::BasicBot) which has two child processes running File::Tail but when exiting, they don't terminate. So I'm killling them using Proc::ProcessTable like this before exiting:

my $parent=$;
my $proc_table=Proc::ProcessTable->new();
for my $proc (@{$proc_table->table()}) {
  kill(15, $proc->pid) if ($proc->ppid == $parent);
}

It works but I get this warning:

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.

What else can I do to kill child processes? The forked process is created using the forkit method in Bot::BasicBot.

Sample script:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

旧人 2024-09-01 18:55:01

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

$SIG{CHLD} = sub { wait };

这样,当子进程退出并且父进程收到 SIGCHLD 信号,它会自动通过 wait 获取子进程。

I'm not familiar with any of the modules you mention, but when I've written forking Perl programs in that past, it has usually sufficed to put this line in the main parent process:

$SIG{CHLD} = sub { wait };

That way, when a child process exits and the parent process gets a SIGCHLD signal, it automatically reaps the child with wait.

待"谢繁草 2024-09-01 18:55:01

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

在分叉之前,设置一个管道,以便分叉的进程可以进行通信:

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 的抓取,它会发出一封电子邮件警报,告知有事情发生。

I'm digging up an old post, but I was looking for an answer to this question and a Google search put this as the top result. So, in case anyone else stumbles on this, here's how I did it.

Before forking, set up a pipe so your forked processes can communicate:

pipe PARENTRECEIVE,CHILDSEND;

Fork your process and have the child send the parent its new process ID immendiately. Then when you think the child is hung (either through a timer or a SIG) you can kill the child process:

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

Sometimes our web server hangs, so I use this to check to see if it's still responding to HTTP GET requests in a reasonable amount of time. If the child doesn't finish grabbing the URL before the parent's timer is up, it sends out an e-mail alert to say something is up.

她如夕阳 2024-09-01 18:55:01

我会担心为什么你的子进程没有正确终止。在“正常”情况下,父进程不必执行任何操作(如果您关心结果,则可以调用 waitpid,或者停止处理直到完成)。

这还不是一个真正的答案——您可能必须将一些代码粘贴到子级中。但有一点建议——从手动调用 fork 的简单程序开始,而不是依赖 CPAN 模块来为您执行此操作。了解系统如何处理多个进程非常重要。然后,当您掌握了这些之后,您就可以利用某些框架来为您处理许多流程。

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

I'd be concerned with why your child processes are not terminating properly. Under "normal" circumstances, the parent shouldn't have to do anything (perhaps call waitpid if you care about the results, or halting processing until they are done).

This isn't really much of an answer yet -- you'll probably have to paste some of the code in the children. But a bit of advice -- start off with simple programs that call fork manually, rather than relying on a CPAN module to do it for you. It's important to understand how multiple processes are handled by the system. Then when you've got that, you can leverage some framework to handle a lot of processes for you.

You should probably also read through perldoc perlfork if you have not done so recently, and try out some of the examples.

蓝礼 2024-09-01 18:55:01

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

As of version 0.82, Bot::BasicBot will kill outstanding child processes (created by forkit()) when exiting.

此刻的回忆 2024-09-01 18:55:01

Fork 将返回父块中子进程的进程 ID。

根据 Mintx 的回答,不需要管道。

my $pid = fork();
if ($pid == 0) {
  #child block
  <do child stuff which might hang>
}
else {
  #parent block
  <do parent stuff>
  <if you think child is hung> {
    kill 1, $child_id;
  }
}

Fork will return the process ID of the child in the parent block.

In response to the answer from Mintx, no pipe is necessary.

my $pid = fork();
if ($pid == 0) {
  #child block
  <do child stuff which might hang>
}
else {
  #parent block
  <do parent stuff>
  <if you think child is hung> {
    kill 1, $child_id;
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文