Как правильно убить дочерние процессы в Perl перед выходом? - PullRequest
5 голосов
/ 21 марта 2010

Я использую бот 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 в 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"; }
}

Ответы [ 4 ]

1 голос
/ 05 марта 2013

Я копаю старое сообщение, но я искал ответ на этот вопрос, и поиск Google поместил это как главный результат. Так что, если кто-то еще наткнется на это, вот как я это сделал.

Перед разветвлением настройте pipe, чтобы ваши разветвленные процессы могли обмениваться данными:

pipe PARENTRECEIVE,CHILDSEND;

Заполните ваш процесс и попросите ребенка немедленно отправить родителю новый идентификатор процесса. Затем, когда вы думаете, что ребенок завис (через таймер или 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-адреса до истечения таймера родителя, он отправляет электронное письмо с предупреждением о том, что что-то не работает.

1 голос
/ 21 марта 2010

Я не знаком ни с одним из упомянутых вами модулей, но когда я писал в прошлом ветвления Perl-программ, обычно было достаточно поместить эту строку в основной родительский процесс:

$SIG{CHLD} = sub { wait };

Таким образом, когда дочерний процесс завершается и родительский процесс получает сигнал SIGCHLD, он автоматически получает дочерний процесс с wait.

1 голос
/ 14 декабря 2011

Начиная с версии 0.82, Bot::BasicBot будет убивать ожидающие дочерние процессы (созданные forkit()) при выходе.

0 голосов
/ 21 марта 2010

Меня беспокоит, почему ваши дочерние процессы не завершаются должным образом. При «нормальных» обстоятельствах родитель не должен ничего делать (возможно, позвоните waitpid, если вам небезразличны результаты, или остановите обработку до их завершения).

Это не очень хороший ответ - вам, вероятно, придется вставить часть кода в детей. Но небольшой совет - начните с простых программ, которые вызывают fork вручную, а не полагайтесь на модуль CPAN, чтобы сделать это за вас. Важно понимать, как система обрабатывает несколько процессов. Затем, когда у вас это получится, вы можете использовать некоторую инфраструктуру для обработки множества процессов за вас.

Вам, вероятно, следует также прочитать perldoc perlfork , если вы не сделали этого недавно, и попробовать некоторые из примеров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...