- Оригинальный адрес:Killing a process and all of its descendants
- Оригинальный автор:igor_sarcevic
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:Цзян Вучжа
- Корректор:TokenJan,portandbridge
Как убить процесс и все его дочерние процессы
Уничтожение процессов в Unix-подобных системах сложнее, чем ожидалось. На прошлой неделе я решал проблему с завершением заданий в Semaphore. Точнее, это вопрос о завершении запущенного процесса в задании. Вот основные моменты, которые я из него вынес:
- Unix-подобные операционные системы имеют сложные межпроцессные отношения: родительские и дочерние процессы, группы процессов, сеансы и лидеры сеансов. Однако в таких операционных системах, как Linux и MacOS, детали этого неодинаковы. Операционные системы, совместимые с POSIX, поддерживают использование отрицательных PID для обозначения групп процессов.
- Использование системного вызова для отправки сигнала всем процессам в сеансе не является тривиальным.
- Дочерний процесс, запущенный с помощью exec, наследует конфигурацию сигнала своего родителя. Например, если родительский процесс игнорирует сигнал SIGHUP, его дочерний процесс также игнорирует сигнал SIGHUP.
- Ответ на вопрос «что происходит внутри группы процессов-сирот» не прост.
Уничтожение родительского процесса не приводит к одновременному уничтожению дочернего процесса.
У каждого процесса есть родительский процесс. мы можем использоватьpstreeилиpsинструмент для наблюдения за этим.
# 启动两个虚拟进程
$ sleep 100 &
$ sleep 101 &
$ pstree -p
init(1)-+
|-bash(29051)-+-pstree(29251)
|-sleep(28919)
`-sleep(28964)
$ ps j -A
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:03 /sbin/init
29051 1470 1470 29051 pts/2 2386 SN 1000 0:00 sleep 100
29051 1538 1538 29051 pts/2 2386 SN 1000 0:00 sleep 101
29051 2386 2386 29051 pts/2 2386 R+ 1000 0:00 ps j -A
1 29051 29051 29051 pts/2 2386 Ss 1000 0:00 -bash
перечислитьpsКоманда может отображать PID (идентификатор процесса) и PPID (идентификатор родительского процесса).
У меня были неправильные предположения о взаимосвязи между родительскими и дочерними процессами. Я думал, что если я убью родительский процесс, то все его дети тоже будут убиты. Однако это неправильно. Вместо этого дочерние процессы станут осиротевшими, а процессы инициализации сделают их родительскими.
Давайте посмотрим, что происходит, когда отношения родитель-потомок между процессами восстанавливаются путем уничтожения процесса bash (текущего родителя команды sleep).
$ kill 29051 # 杀死 bash 进程
$ pstree -A
init(1)-+
|-sleep(28919)
`-sleep(28965)
Поведение переназначения родительского процесса мне кажется странным. Например, когда я подключаюсь к серверу по SSH, запускаю процесс, а затем выхожу, запущенный мной процесс будет уничтожен. Я ошибочно думал, что это поведение по умолчанию в Linux. Когда я покидаю сеанс SSH, завершение процесса связано с группой процессов, ведущим процессом сеанса и контролирующим терминалом.
Что такое группы процессов и процессы лидеров сеансов?
Давайте еще раз посмотрим на приведенный выше случай.ps jвывод команды.
$ ps j -A
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:03 /sbin/init
29051 1470 1470 29051 pts/2 2386 SN 1000 0:00 sleep 100
29051 1538 1538 29051 pts/2 2386 SN 1000 0:00 sleep 101
29051 2386 2386 29051 pts/2 2386 R+ 1000 0:00 ps j -A
1 29051 29051 29051 pts/2 2386 Ss 1000 0:00 -bash
В дополнение к взаимосвязи процессов родитель-потомок, представленной PPID и PID, между процессами существуют еще две связи:
- Группа процессов, представленная PGID
- сеанс, представленный SID
Мы можем наблюдать группы процессов в средах оболочки, которые поддерживают управление заданиями, например.bashиzsh, которые создают группу процессов для каждой переданной команды. Группа процессов — это набор из одного или нескольких процессов (обычно связанных с заданием), которые могут получать сигналы от одного и того же терминала. Каждая группа процессов имеет уникальный идентификатор группы процессов.
# 启动一个由 tail 和 grep 命令组成的进程组
$ tail -f /var/log/syslog | grep "CRON" &
$ ps j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
29051 19701 19701 29051 pts/2 19784 SN 1000 0:00 tail -f /var/log/syslog
29051 19702 19701 29051 pts/2 19784 SN 1000 0:00 grep CRON
29051 19784 19784 29051 pts/2 19784 R+ 1000 0:00 ps j
29050 29051 29051 29051 pts/2 19784 Ss 1000 0:00 -bash
Отметим, что в первой половинеtailиgrepPGID тот же.
Сеанс — это набор групп процессов, обычно состоящий из контролирующего терминала и процесса-лидера сеанса. Если в сеансе есть управляющий терминал, он имеет одну группу процессов переднего плана, за исключением управляющего терминала, все остальные группы процессов в сеансе являются группами фоновых процессов.
Не все процессы bash являются сеансами, но когда вы входите на удаленный сервер с помощью SSH, вы обычно получаете сеанс. Когда bash запускается как процесс лидера сеанса, он передает сигнал SIGHUP своим дочерним процессам. То, как распространяется сигнал SIGHUP, является основной причиной, по которой я всегда считал, что дочерний процесс умрет вместе с родительским процессом.
Сеансы не реализованы последовательно в Unix
В приведенном выше примере вы можете заметить, где появляется SID (идентификатор сеанса процесса). Это идентификатор, общий для всех процессов в сеансе.
Однако вы должны иметь в виду, что не все системы Unix следуют этой реализации. Единая спецификация UNIX говорит только о «процессе лидера сеанса», в нем нет «идентификатора сеанса», такого как идентификатор процесса или идентификатор группы процессов. Процесс лидера сеанса — это отдельный процесс с уникальным идентификатором процесса, поэтому идентификатор сеанса, о котором мы можем говорить, — это идентификатор процесса лидера сеанса.
System V Release 4 представила идентификаторы сеансов.
На практике это означает, что вы можетеpsдля получения идентификатора сеанса, но в BSD и его вариантах (например, MacOS) идентификатор сеанса не существует или всегда равен нулю.
Убить все процессы в группе процессов или сеансе
Мы можем использовать этот PGID для отправки сигнала всей группе процессов с помощью команды kill:
$ kill -SIGTERM -- -19701
мы используем отрицательное число-19701Отправьте сигнал группе процессов. Если мы передаем положительное число, это число будет рассматриваться как идентификатор процесса для завершения процесса. Если мы передаем отрицательное число, оно обрабатывается как PGID и используется для завершения всей группы процессов.
Отрицательные числа исходят из прямого определения системного вызова.
Уничтожение всех процессов в сеансе — это совсем другое. Как мы упоминали в предыдущем разделе, в некоторых системах отсутствует понятие идентификатора сеанса. Даже системы с идентификаторами сеанса, такие как Linux, не предоставляют системный вызов для уничтожения всех процессов в сеансе. вам нужно пересечь/procВыведите дерево процессов, соберите все SID и убейте процессы один за другим.
Pgrep реализует алгоритм обхода, сбора и уничтожения процессов по идентификатору сеанса. Используйте следующие команды:
pkill -s <SID>
Сигналы, игнорируемые nohup, распространяются на дочерние процессы.
Сигналы, которые игнорируются, как быnohupИгнорируемые сигналы распространяются на все дочерние элементы процесса. Этот способ распространения сигнала был самым узким местом, с которым я столкнулся при устранении неполадок на прошлой неделе.
Моя программа является агентом для запуска команд bash, и я проверил в программе то, что я установил сеанс bash с управляющим терминалом. Управляющий терминал является лидером сеанса для других запущенных процессов в сеансе bash. Мое дерево процессов выглядит так:
agent -+
+- bash (session leader) -+
| - process1
| - process2
Я предполагаю, что когда я завершаю сеанс bash с помощью SIGHUP , его дочерние процессы также уничтожаются одновременно. Интеграционные тесты на агенте также подтверждают это.
Однако я проигнорировал этот прокси какnohupначалось. когда вы используетеexecКогда запускается дочерний процесс, точно так же, как мы запускаем процесс bash в агенте, он наследует состояние сигнала от своего родительского процесса.
Последний вывод меня удивил.
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллекти другие поля, если вы хотите видеть больше качественных переводов, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.