2015-09-01 1 views
0

Я использую MCE, чтобы что-то делать, и он работает хорошо. Мне нужно посмотреть, как произойдет событие, а затем развить процесс 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 хвостовым процессам).

С помощью setid процессы диспетчера 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 

Если бы я отправить SIGTERM в 29002 выше, я бы ожидать, что процесс, чтобы умереть вместе с 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

+0

Вы отправляете SIGTERM, но родитель получил SIGINT? – ikegami

+1

'kill ('INT', $ _is_MSWin32? - $$: -getpgrp);' в MCE :: Сигнал, вероятно, отвечает. – ikegami

+0

@ikegami Спасибо, что ты прав. Я взломал Signal.pm, и есть несколько случаев, когда группа процессов убита, и есть ссылки на $ main_proc_id (родительский pid) в этих убийствах. Я уверен, что вокруг этого есть правильный путь, но это выглядит как первопричина. Благодаря! –

ответ

2

Модуль кэширует PID на загрузке модуля. не исправить это, выполнив следующие пост-вилы:

$MCE::Signal::main_proc_id = $$; 

еще лучше, задержка загрузки MCE, пока после развилки. Я бы сделать это путем перемещения

use MCE::Loop; 
use MCE::Signal '-setpgrp'; 

в модуль (скажем Worker.pm), и путем перемещения кода ребенка в суб имени run в том же модуле, а затем выполнить следующие пост-вилы:

require Worker; 
Worker::run(); 

script:

#!/usr/bin/perl 

use strict; 
use warnings; 

use POSIX qw(setsid); 

my $name = shift; 

my @pids; 
while (@pids < 2) { 
    my $pid = fork(); 

    if (!defined $pid) { 
     print "Can't fork: $!\n"; 
    } 

    elsif ($pid == 0) { 
     (setsid() != -1) 
      or die "Can't start a new session: $!"; 

     require Worker; 
     Worker::run($name); 
     exit; 
    } 

    else { 
     print $pid."\n"; 
     push(@pids, $pid); 
    } 
} 

for my $pid (@pids) { 
    waitpid($pid, 0); 
} 

Worker.pm:

package Worker; 

use strict; 
use warnings; 

use MCE::Loop; 
use MCE::Signal '-setpgrp'; 

my $mce_maxWorkers = 2; 
my $mce_chunkSize = 1; 

sub run { 
    my $name = shift; 

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

1; 
+0

Мне пришлось добавить пакет Worker; на вершине Worker.pm (я переименовал его), но в остальном это работает отлично! Спасибо, что нашли время, чтобы работать с ним вместе со мной. Я смогу принять это и реализовать его в своей основной программе довольно быстро. :) –

+0

argh, второй раз я забыл, что на этой неделе. Исправлена. – ikegami

Смежные вопросы