#linux #process #process-group
#linux #процесс #process-group
Вопрос:
Я хотел бы запустить процесс в его собственной группе процессов (или, альтернативно, изменить его группу после запуска) и:
- должны ли процессы в группе отвечать на
Ctrl
C
с терминала - получить идентификатор группы процессов, чтобы я мог завершить все процессы в группе с помощью
kill
команды.
Примечание: Я пытался setsid prog [args]
, но процессы не реагируют на Ctrl C из терминала, и я не смог получить новый идентификатор группы процессов.
Я также пытался изменить группу процессов с помощью Perl setpgrp($pid, $pid)
и POSIX::setpgid($pid, $pid)
, безрезультатно.
Редактировать: Большая проблема:
У меня есть процесс (однопоточный; назовем его «продуктивный» процесс P
), который запускает множество дочерних процессов синхронно (один за другим; он запускает новый, когда завершается предыдущий дочерний процесс). Из терминала я хочу иметь возможность убивать P
и дерево процессов под ним. Для этого я мог бы просто организовать завершение процессов в P
группе. Однако поведение по умолчанию таково, что P
процесс находится в группе его родительского процесса. Это означает, что P
родительский процесс будет уничтожен, если я уничтожу все процессы в P
его группе, если только у меня не есть P
и его дерево не находится в их собственной группе.
Мое намерение состоит в том, чтобы уничтожить P
и дерево под ним, но не P
родительское. Кроме того, я не могу изменить сам код P
.
Комментарии:
1. Пожалуйста, поясните, какое отличие от поведения запуска процесса по умолчанию (как показано ninjalj ниже) вам нужно выполнить?
2. Я надеюсь, что правка, которую я добавил выше (большая проблема), поможет прояснить намерение.
3. Вы можете
fork
иsetpgrp
запустить процесс в новой группе процессов. Тогда вместо P и его дочерних элементов у вас будут Pp, Pc и дочерние элементы Pc. Поскольку вы сразу жеsetpgrp
запустили компьютер послеfork
, он будет находиться в своей собственной группе процессов, так что вы можете уничтожить его и его дочерние элементы за один раз. Установите Ppwait
, и он будет ждать, пока компьютер не умрет, а затем завершит работу (или что бы вы ни хотели, чтобы он делал).4. это именно то, что требовалось. Спасибо!! Осталось сложить на место только один кусочек головоломки. Я хочу, чтобы мой родительский Perl-скрипт завершался со статусом ошибки, указывающим, что он был прерван. Пожалуйста, посмотрите мой пост в разделе ответов ниже.
Ответ №1:
Что значит «запустить процесс в его собственной группе процессов»? Оболочка запускает процессы в их собственных группах процессов, вот как она выполняет управление заданиями (имея группу процессов для процессов на переднем плане и несколько групп процессов для каждого конвейера, запущенного в фоновом режиме).
Чтобы убедиться, что оболочка запускает новую группу процессов для каждого конвейера, вы можете сделать это:
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. Интересный момент… какова цель? Собственная группа процессов или собственный идентификатор сеанса? Я вроде как предположил, что позже, но нам придется подождать, пока постер прояснит ситуацию
2. @Chris: Я думаю, что использовался OP,
setsid
потому что там нет никакойsetpgrp
утилиты.3. @ninjalj: Возможно, это так. Интересно, какова была цель. В любом случае, я кое-что узнал, когда собирал свой, возможно, не относящийся к делу ответ 😉
4. @Chris: ваш ответ является актуальным. Я просто добавлял другой угол.
5. @ninjalj: Вы не прогадали с мыслью о Perl. Процесс «profilic», о котором я упоминал выше, является процессом Perl, который вызывает system повторно несколько раз. Когда его текущий дочерний процесс завершается, P создает другой дочерний процесс, не обращая внимания на тот факт, что предыдущий дочерний процесс был прерван. Моя цель — сделать так, чтобы P и дерево процессов под ним были уничтожены при прерывании с терминала, но не родительский процесс P
Ответ №2:
РЕДАКТИРОВАТЬ: Если то, что вы хотели сделать, это использовать setsid, но найти идентификатор сеанса и / или pid результирующего процесса:
Если вы запустите процесс с помощью команды setsid, он не будет подключен к вашему терминалу, поэтому, конечно, он не будет реагировать на ctrl-c.
Вы могли бы найти это, просматривая выходные данные
ps x -O sid
или что-то более ограниченное, например
ps x -o %c,%p,sid
Или простой поиск через proc / [pid] / stat всех записей и просмотр идентификатора сеанса и всего остального, что представляет интерес (подробнее см. man proc)
Страница руководства для setsid не предоставляет никаких флагов для непосредственного генерирования выходных данных, но вы могли бы тривиально создать свою собственную версию, которая выводит нужную информацию, путем изменения стандарта.
Например, возьмите копию setsid.c из одного из результатов для
http://www.google.com/codesearch?as_q=setsidamp;as_package=util-linux
Прокомментируйте включение nls, параметры локали и макрос ошибки _(«»), который вызовет проблемы, а затем добавьте это прямо перед строкой execvp:
printf("process will be pid %d sid %dn", getpid(), getsid(0));
Комментарии:
1. Что я должен был сказать, так это «какой-то макрос, недоступный в однофайловой сборке, который использовался для отображения сообщения об ошибке»
Ответ №3:
Вот ответ в коде Perl, следующий предложениям ninjalj выше:
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}
}
Еще раз большое спасибо!
Комментарии:
1. Вы всегда можете
kill INT => $$
вместоexit
, хотя я не уверен, что это будет так просто завершить таким образом.2. OTOH
perl -e 'kill INT => $$;'; echo $?
показывает 130 в моем окне. Итак, для меня это было быexit 130
3. В любом случае, я не уверен, что вам нужно перехватывать SIGINT, ^ C должен отправить его всей группе процессов, ваш дочерний процесс Perl игнорирует его, но он получит код выхода из
system
вызова.4. Как видно из
perl -e 'exit system"sleep 5"'; echo $?
и ^C5. 1. Мне нужно перехватить SIGINT в оболочке (родительской), потому что мне нужно уничтожить процессы в группе, возглавляемой prolific. 2. Я бы использовал выход 130. Я не уверен, каким будет эффект
kill INT => $$
в обработчике сигналов.