Как убить системные вызовы Perl, когда основной скрипт убит? - PullRequest
6 голосов
/ 23 апреля 2009

Предыдущие ответы на эти вопросы были сосредоточены на вилках:

На этот вопрос я просто спрашиваю о вызовах функции 'system'.

Скажем, у меня есть скрипт с именем sleep.pl :

use strict;
use warnings;
sleep(300);

У меня есть скрипт с именем kill.pl

use strict;
use warnings;
system("sleep.pl");

Я запускаю kill.pl и с помощью ps нахожу идентификатор процесса kill.pl и уничтожаю его (не используя kill -9, просто обычное kill)

sleep.pl все еще спит.

Я полагаю, что решение моего вопроса включает в себя обработчик SIG, но что мне нужно поместить в обработчик, чтобы уничтожить дочерний процесс?

Ответы [ 3 ]

3 голосов
/ 23 апреля 2009
use strict;
use warnings;
setpgrp $$, 0;
system("sleep.pl");
END {kill 15, -$$}

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

$ perl -e 'system("sleep 100")' &
[1] 11928
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Ss     0:01 /bin/bash
11928 pts/1    S      0:00  \_ perl -e system("sleep 100")
11929 pts/1    S      0:00  |   \_ sleep 100
11936 pts/1    R+     0:00  \_ ps f
$ kill %1
[1]+  Terminated              perl -e 'system("sleep 100")'
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Rs     0:01 /bin/bash
11949 pts/1    R+     0:00  \_ ps f

Как это работает? Shell (bash в моем случае) должен установить ваш процесс в качестве лидера группы, если вы работаете в фоновом режиме. Тогда, если вы используете kill %? синтаксис, оболочка убивает группу правильным образом. Сравните это:

$ perl -e 'system("sleep 100")' &
[1] 12109
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Rs     0:01 /bin/bash
12109 pts/1    S      0:00  \_ perl -e system("sleep 100")
12113 pts/1    S      0:00  |   \_ sleep 100
12114 pts/1    R+     0:00  \_ ps f
$ kill 12109
[1]+  Terminated              perl -e 'system("sleep 100")'
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Ss     0:01 /bin/bash
12124 pts/1    R+     0:00  \_ ps f
12113 pts/1    S      0:00 sleep 100

Но kill %? работает следующим образом:

$ perl -e 'system("sleep 100")' &
[1] 12126
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Rs     0:01 /bin/bash
12126 pts/1    S      0:00  \_ perl -e system("sleep 100")
12127 pts/1    S      0:00  |   \_ sleep 100
12128 pts/1    R+     0:00  \_ ps f
$ kill -12126
[1]+  Terminated              perl -e 'system("sleep 100")'
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Ss     0:01 /bin/bash
12130 pts/1    R+     0:00  \_ ps f
3 голосов
/ 23 апреля 2009

Используйте setsid , чтобы сделать ваш процесс новым лидером группы. Затем вы можете отправить уничтожение идентификатору группы и уничтожить все процессы, принадлежащие этой группе. Все процессы, которые вы порождаете из процесса лидера, наследуют идентификатор группы и принадлежат к вашей недавно созданной группе. Таким образом, отправка убийства в группу убьет их всех. Единственная хитрость в том, что для того, чтобы иметь возможность использовать setsid, вы должны закрыть свой стандарт в и вывести его, так как это требование для setsid.

2 голосов
/ 07 июля 2010

Ваш вопрос на самом деле является конкретным примером более общего вопроса "как обеспечить умирание ребенка, когда умирает родитель" Там просто не обойтись. Там нет ничего особенного в системе (); он просто разветвляет дочерний процесс и ожидает его завершения.

system () - это примерно так:

sub system 
{
    my $kidpid = fork;
    if ( $kidpid )
    {
        waitpid $kidpid; 
          # parent process blocks here waiting for the child process to return
    }
    else
    {
        exec( @_ );
    }
}

Убить группу процессов - это ваш единственный вариант.

...