2015-07-07 3 views
3

Я хочу, чтобы все дочерние процессы умирали, когда я убивал perl-процесс, который использует ForkManager. В приведенном ниже коде, если я запустил его и ударил ctrl + c В то время как линия сна работает, процесс сна убит, но линии print затем выполняются одновременно до завершения скрипта. В идеале я хотел бы, чтобы прерывание немедленно прекратило выполнение. Что я могу сделать?ForkManager SIGINT только убивает текущий процесс в fork

#!/usr/bin/perl -w 
use Parallel::ForkManager; 

main { 
    my $fork1 = new Parallel::ForkManager(8); 
    while (1) { 
     $fork1->start and next; 
     system("sleep 15s"); 
     print "Still going!" 
     $fork1->finish; 
    } 
    fork1->wait_all_children; 
} 
+1

'system' также порождает процесс, я думаю, если вы измените' систему («15s сна») 'для Перла' сна 15; 'вы не увидите такое же поведение. –

ответ

2

во-первых - использование system означает, что вы могли бы иметь что-то странное произошло, потому что ... тогда вы позволяете все, что вы вызов чтобы делать вещи для обработки сигналов самостоятельно.

Это может быть вашей проблемой.

Однако в противном случае то, что вы можете сделать с помощью perl, - это настроить обработчики сигналов - что делать, если сигнал получен этим процессом. По умолчанию - сигналы либо установлены на «выход», либо «игнорировать».

Вы можете увидеть, что это в настоящее время с помощью print Dumper \%SIG;

Однако самое простое решение для вас проблемы, я думаю, было бы установить обработчик ловушки SIGINT, а затем отправить kill к текущей группе процессов.

Поведение kill, когда число PROCESS равно нулю или отрицательно, зависит от операционной системы. Например, в системах, соответствующих POSIX, нуль будет сигнализировать текущую группу процессов, -1 будет сигнализировать все процессы, а любой другой отрицательный номер PROCESS будет действовать как отрицательный номер сигнала и убить всю указанную группу процессов.

$SIG{'INT'} = sub { 
    kill ('TERM', -$$); 
}; 
6

Согласно perldoc system, system фактически игнорирует как SIGINT и SIGQUIT:

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

Так что, если вы хотите, чтобы ваши процессы, чтобы остановить выполнение, если вы SIGINT во время system вызова, вам нужно реализовать эту логику самостоятельно:

#!/usr/bin/perl -w 
use Parallel::ForkManager; 

main { 
    my $fork1 = new Parallel::ForkManager(8); 
    while (1) { 
     $fork1->start and next; 
     print "Sleeping..."; 
     system("sleep 15s") == 0 or exit($?); 
     print "Still going!"; 
     $fork1->finish; 
    } 
    fork1->wait_all_children; 
} 

ИЛИ более разумным подходом является использование встроенного Perl в sleep:

#!/usr/bin/perl -w 
use Parallel::ForkManager; 

main { 
    my $fork1 = new Parallel::ForkManager(8); 
    while (1) { 
     $fork1->start and next; 
     print "Sleeping..."; 
     sleep 15; 
     print "Still going!"; 
     $fork1->finish; 
    } 
    fork1->wait_all_children; 
} 
+1

Отлично! Я не понимал, что система перехватывает SIGINT. (И причина использования system() заключается в том, что это всего лишь один из примеров многих команд, не связанных с системой ...) – donutbrew

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