Как запустить процесс в своей собственной группе процессов? - PullRequest
7 голосов
/ 27 апреля 2011

Я хотел бы запустить процесс в своей собственной группе процессов (или, альтернативно, изменить его группу после запуска) и:

  • имеют процессы в группе, отвечающие на Ctrl + C из терминала
  • получить идентификатор группы процессов, чтобы я мог завершить все процессы в группе с помощью команды kill.

Примечание: я пытался setsid prog [args], но процессы не отвечают на Ctrl + C с терминала, и я не могу получить новый идентификатор группы процессов.

Я также пытался изменить группу процессов через setpgrp($pid, $pid) и POSIX::setpgid($pid, $pid) в Perl, но безрезультатно.

Редактировать: Большая проблема:

У меня есть процесс (однопоточный; назовем его «плодовитым» процессом P), который запускает много дочерних процессов синхронно (один за другим; он запускает новый, когда предыдущий дочерний процесс завершается). Из терминала я хочу иметь возможность убить P и дерево процессов под ним. Для этого я мог бы просто организовать уничтожение процессов в группе P. Однако по умолчанию поведение P находится в группе его родительского процесса. Это означает, что родительский элемент P будет убит, если я уничтожу все процессы в группе P, если у меня не будет P и его дерево не будет в их собственной группе.

Я собираюсь убить P и дерево под ним, но не родитель P. Также я не могу изменить сам код P.

Ответы [ 3 ]

3 голосов
/ 28 апреля 2011

Что вы подразумеваете под «запустить процесс в своей собственной группе процессов»?Оболочка запускает процессы в своих собственных группах процессов, вот как она выполняет управление заданиями (имея группу процессов для процессов на переднем плане и несколько групп процессов для каждого конвейера, запущенного в фоновом режиме).

Чтобы увидеть этооболочка запускает новую группу процессов для каждого конвейера, вы можете сделать это:

ps fax -o pid,pgid,cmd | less

, которая покажет что-то вроде:

11816 11816  |   \_ /bin/bash
4759   4759  |       \_ ps fax -o pid,pgid,cmd
4760   4759  |       \_ less

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

Редактировать:

Я думаю, я знаю, к чему вы клоните.Вы звоните system из Perl.По-видимому, sh -c не создает новые группы процессов, поскольку это оболочка без управления заданиями.

Я бы сделал fork, затем дочерний:

setpgrp;
system("ps fax -o pid,pgid,cmd");

и wait на родителя.

1 голос
/ 27 апреля 2011

РЕДАКТИРОВАТЬ: Если вы хотели использовать setid, но найти идентификатор сеанса и / или pid результирующего процесса:

Если вы запустите процесс с помощью команды setsid, он не будет подключен к вашему терминалу, поэтому, конечно, он не будет реагировать на ctrl-c.

Вы можете найти его, просмотрев вывод

ps x -O sid 

или что-то более ограниченное, например

ps x -o %c,%p,sid

Или простой троллинг через proc / [pid] / stat для всех записей и просмотр идентификатора сеанса и всего остального, что интересует (подробности смотрите в man proc)

Страница man для setsid не предоставляет никаких флагов для непосредственного генерирования вывода, но вы можете тривиально создать свою собственную версию, которая распечатывает нужную информацию, изменяя стандарт.

Например, возьмите копию setsid.c из одного из результатов для

http://www.google.com/codesearch?as_q=setsid&as_package=util-linux

Закомментируйте nls include, материал локали и макрос ошибки _ (""), который вызовет проблемы, а затем добавьте это прямо перед строкой execvp:

    printf("process will be pid %d sid %d\n", getpid(), getsid(0));
0 голосов
/ 28 апреля 2011

Вот ответ в коде Perl, следуя рекомендациям ниндзяля выше:

prolific_wrapper.pl

my $pid = fork();
if (not defined $pid) {

    die 'resources not available';

} elsif ($pid == 0) {

    # CHILD
    setpgrp;
    exit system(prolific => @ARGV);

} else {

    # PARENT
    my $was_killed = 0;
    local $SIG{INT} = sub {
        say 'kill prolific and its tree ...';
        kill KILL => -$pid;
        $was_killed = 1;
    };
    wait;
    my $child_status = $?;
    $SIG{INT} = 'DEFAULT';
    if ($was_killed) {kill INT => $$}
    else {exit $child_status}

}

Большое спасибо еще раз!

...