Процесс потомков

20

Я пытаюсь построить контейнер процесса. Контейнер будет запускать другие программы. Например, bash-скрипт, запускающий фоновые задачи с использованием '&'.

Важная особенность, которая мне нужна, заключается в следующем: когда я убиваю контейнер, все, что было создано под ним, должно быть уничтожено. Не только прямые дети, но и их потомки.

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

Я верю в то, чего я хочу достичь, потому что, когда вы закрываете xterm, все, что в нем работает, уничтожается, если оно не было nohup'd. Это включает осиротевшие процессы. Вот что я хочу воссоздать.

У меня есть идея, что то, что я ищу, включает в себя сессии Unix.

Если бы существовал надежный способ идентифицировать всех потомков процесса, было бы полезно иметь возможность отправлять им и произвольные сигналы. например, SIGUSR1.

Крейг Тернер
источник
Что ж, уничтожение родительского процесса отправляет SIGHUPего непосредственным дочерним процессам. Стандартный обработчик сигнала зависания прерывает выполнение процесса, поэтому маршрут по умолчанию - убить всех потомков. Узнайте больше о процессах и группах процессов.
alex
Закрытие xterm убивает все, что появилось в xterm, потому что TTY уничтожен. Если вы можете придумать способ создания tty, который могут использовать дочерние процессы, вы можете уничтожить TTY и выполнить то же самое. Любой процесс, который не закрывал этот TTY (nohup & friends), получит SIGHUP.
Патрик

Ответы:

23

Если вы отправите сигнал процессу, этот процесс будет уничтожен. Интересно, как слух, что убийство процесса также убивает другие процессы, начался, это кажется особенно нелогичным.

Однако существуют способы уничтожить более одного процесса. Но вы не будете посылать сигнал одному процессу. Вы можете уничтожить целую группу процессов , отправив сигнал на -1234, где 1234 - это PGID (идентификатор группы процессов), который является PID лидера группы процессов. Когда вы запускаете конвейер , весь конвейер начинается как группа процессов (приложения могут изменить это, вызвав setpgidили setpgrp).

Когда вы запускаете процессы в фоновом режиме ( foo &), они находятся в своей собственной группе процессов. Группы процессов используются для управления доступом к терминалу; обычно только передняя группа процессов имеет доступ к терминалу. Фоновые задания остаются в том же сеансе , но нет возможности убить весь сеанс или даже перечислить группы процессов или процессы в сеансе, так что это мало поможет.

Когда вы закрываете терминал, ядро ​​отправляет сигнал SIGHUPвсем процессам, которые имеют его в качестве управляющего терминала . Эти процессы формируют сеанс , но не все сеансы имеют управляющий терминал. Поэтому для вашего проекта одна возможность состоит в том, чтобы запустить все процессы в их собственном терминале, созданном с помощью скрипта , экрана и т. Д. Завершить процесс эмулятора терминала, чтобы уничтожить содержащиеся в нем процессы (при условии, что они не были переданы setsid).

Вы можете обеспечить большую изоляцию, запустив процессы под своим собственным пользователем, который больше ничего не делает. Тогда легко убить все процессы: запустить kill( системный вызов или утилиту ) от имени этого пользователя и использовать -1 в качестве аргумента PID для уничтожения, что означает «все процессы этого пользователя».

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

Жиль "ТАК - прекрати быть злым"
источник
Если вы программируете свои собственные процессы, то вы можете использовать что-то, например:, prctl(PR_SET_PDEATHSIG, SIGHUP);больше информации: man7.org/linux/man-pages/man2/prctl.2.html
Алексис Уилк
Жиль, вы упоминаете об этом - «Когда вы закрываете терминал, ядро ​​посылает сигнал SIGHUP всем процессам, которые имеют его в качестве управляющего терминала». Исходя из этого, я предполагаю, что терминал отправляет SIGHUP руководителю сеанса (оболочке), который перенаправляет его всем группам процессов внутри сеанса. Какой из двух будет правильным?
Ирувар
4

Внутри родительского скрипта перехватите сигнал kill и убейте всех детей. Например,

#!/bin/bash
# kill the parent and children together
trap "kill 0" EXIT
# create all the children
for n in $(seq 1 100)
do
    ( echo "begin $n"; sleep 60; echo "end $n" ) &
done
# wait for the children to complete
wait
Андрей Гилмартин
источник
2

Надежный способ идентифицировать всех потомков процесса - использовать команду, pstree <pid>где pid - это идентификатор вашего родительского процесса.

Прочитайте справочную страницу pstree здесь .

Чтобы сообщить всем членам группы процессов: killpg(<pgrp>, <sig>);
где pgrp - номер группы процессов, а sig - сигнал.

Чтобы дождаться детей в указанной группе процессов: waitpid(-<pgrp>, &status, ...);

Альтернативой тому, что вы делаете, является запуск вашего контейнера процессов в новой оболочке bash. Создайте новую оболочку bash с помощью команды bashи запустите ваши процессы. Когда вы хотите, чтобы все процессы были завершены, выйдите из оболочки с помощью команды exit.

Крис Тинг
источник
Я думаю killpg позволит мне делать то, что мне нужно. Благодарю.
Крейг Тернер
1

использование

unshare -fp --kill-child -- yourprogram

Если вы убьете unshare, все дочерние процессы (которые yourprogramмогли появиться) будут уничтожены.

Теперь это возможно с util-linux 2.32; Я реализовал это вверх по течению . Для этого требуются пользовательские пространства имен (опция конфигурации ядра CONFIG_USER_NS=y) или привилегии root. Смотрите также здесь .

NH2
источник
0

Команда rkill из пакета pslist отправляет данный сигнал (или SIGTERMпо умолчанию) указанному процессу и всем его потомкам:

rkill [-SIG] pid/name...
Onlyjob
источник
0

Еще один вариант убить всех потомков оболочки: jobs -p | xargs -n 1 pkill -P

Даг Фоули
источник