В каком порядке следует отправлять сигналы для изящного завершения процессов?

В comment на этот ответ другого question, комментатор говорит:

Не используйте kill -9, если не считать абсолютно необходимо! SIGKILL не может попасть в ловушку убитая программа не может процедуры выключения для удаления, например, временные файлы. Сначала попробуйте HUP (1), затем INT (2), затем QUIT (3)

Я в принципе согласен с SIGKILL, но остальное для меня новость. Учитывая, что сигнал по умолчанию, отправленный kill, равен SIGTERM, я ожидаю, что это наиболее часто ожидаемый сигнал для грациозного отключения произвольного процесса. Кроме того, я видел, что SIGHUP используется для неисчерпающих причин, например, говоря демонам "перечитать ваш файл конфигурации". И мне кажется, что SIGINT (такое же прерывание, которое вы обычно получаете с помощью Ctrl-C, верно?) Не так широко поддерживается, как должно быть, или заканчивается довольно беззаботно.

Учитывая, что SIGKILL - последнее средство — Какие сигналы и в каком порядке следует отправить произвольному процессу, чтобы максимально закрыть его?

Пожалуйста, подтвердите свои ответы с помощью подтверждающих фактов (помимо личных предпочтений или мнений) или ссылок, если сможете.

Примечание. Меня особенно интересуют лучшие практики, которые включают рассмотрение bash/Cygwin.

Изменить: Пока никто не упоминает INT или QUIT, и здесь упоминается HUP. Есть ли причина включать их в упорядоченный процесс-убийство?

Ответ 1

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

Некоторые люди считают, что стандартный способ завершения процесса - это послать ему множество сигналов, таких как HUP, INT, TERM и, наконец, KILL. Это нелепо. Правильный сигнал для завершения - SIGTERM, и если SIGTERM не прекращает процесс мгновенно, как вы, возможно, предпочитаете, потому что приложение выбрало для обработки сигнала. Это означает, что у него есть очень веская причина не сразу прекратить работу: он получил работу по очистке. Если вы прерываете эту очистку с другими сигналами, не сообщается, какие данные из памяти еще не сохранены на диске, какие клиентские приложения остаются висящими или прерывается ли это "среднее предложение", которое эффективно разрушает данные.

Для получения дополнительной информации о том, каков реальный смысл сигналов, см. sigaction (2). Не путайте "Действие по умолчанию" с "Описание", это не одно и то же.

SIGINT используется для сигнализации интерактивного "прерывания клавиатуры" процесса. Некоторые программы могут обрабатывать ситуацию особым образом для конечных пользователей.

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

SIGKILL используется для принудительного удаления процесса из ядра. Специально в том смысле, что он не является фактически сигналом к ​​процессу, а скорее напрямую интерпретируется ядром.

Не отправлять SIGKILL. SIGKILL, безусловно, никогда не будет отправляться по сценариям. Если приложение обрабатывает SIGTERM, это может занять секунду для очистки, может потребоваться минута, может потребоваться час. В зависимости от того, что приложение должно выполнить, прежде чем оно будет готово к завершению. Любая логика, которая "предполагает" последовательность очистки приложения, взята достаточно долго и должна быть ярлыком или SIGKILLed после X секунд просто неверно.

Единственная причина, по которой для приложения потребуется SIGKILL для завершения, является ли что-то избитым во время его очистки. В этом случае вы можете открыть терминал и SIGKILL вручную. Кроме того, единственная причина, по которой вы SIGKILL что-то, потому что вы ХОТИТЕ предотвратить ее очистку.

Это не потому, что половина мира использует SIGKILL через 5 секунд, чтобы это не было ужасно неправильно.

Ответ 2

Обычно вы отправляете SIGTERM, по умолчанию - kill. Это по умолчанию. Только если программа не выключается в течение разумного промежутка времени, вы должны прибегнуть к SIGKILL. Но учтите, что при SIGKILL программа не имеет возможности очищать вещи, и данные могут быть повреждены.

Что касается SIGHUP, HUP означает "повесить трубку" и исторически означает, что модем отключен. Это по существу эквивалентно SIGTERM. Причина, по которой демонам иногда использовать SIGHUP для перезагрузки или перезагрузки конфигурации, заключается в том, что демоны отключаются от любых управляющих терминалов, поскольку демона им не нужны, и поэтому они никогда не получат SIGHUP, чтобы сигнал считался "освобожденным" для обычный использование. Не все демоны используют это для перезагрузки! Действие по умолчанию для SIGHUP должно заканчиваться, и многие демоны ведут себя таким образом! Поэтому вы не можете вслепую отправить SIGHUP демонам и ожидать, что они выживут.

Изменить: SIGINT, вероятно, нецелесообразно прекращать процесс, поскольку он обычно привязан к ^C или тому, что параметр терминала должен прерывать программу. Многие программы фиксируют это в своих целях, поэтому достаточно распространены, чтобы он не работал. SIGQUIT обычно имеет значение по умолчанию для создания дампа ядра, и если вы не хотите, чтобы файлы ядра, лежащие вокруг него, тоже не были хорошим кандидатом.

Сводка: если вы отправляете SIGTERM, и программа не умирает в течение вашего таймфрейма, отправьте ее SIGKILL.

Ответ 3

SIGTERM на самом деле означает отправку приложения сообщения: "Вы были бы так добры и покончили бы самоубийством". Он может быть захвачен и обработан приложением для запуска кода очистки и завершения работы.

SIGKILL не может быть захвачен приложением. Приложение может быть уничтожено ОС без каких-либо шансов на очистку.

Обычно для отправки SIGTERM сначала спящего время, а затем отправьте SIGKILL.

Ответ 4

Краткий ответ: Отправить SIGTERM, через 30 секунд, SIGKILL. То есть, отправьте SIGTERM, подождите немного (это может варьироваться от программы к программе, вы можете лучше знать свою систему, но достаточно 5-30 секунд. При выключении машины вы можете увидеть, что она автоматически ждет до 1 30 секунд Почему, в конце концов, торопитесь?), Затем отправьте SIGKILL.

Разумный ответ: SIGTERM, SIGINT, SIGKILL Этого более чем достаточно. Этот процесс будет очень вероятно, заканчиваться до SIGKILL.

Длительный ответ: SIGTERM, SIGINT, SIGQUIT, SIGABRT, SIGKILL

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

Независимо от того, какой ответ вы выберете из этого объяснения, помните об этом!

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

Итак, вы должны думать, как себя, как программиста. Вы бы закодировали обработчик функции, скажем, SIGHUP чтобы выйти из программы, которая связана с чем-то, или вы бы зацикливали ее, чтобы попытаться подключиться снова? Это главный вопрос! Вот почему важно просто посылать сигналы, которые означают то, что вы намерены.

Почти глупый длинный ответ:

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

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

Сигналы со звездочкой (*) НЕ рекомендуются. Важно то, что вы, возможно, никогда не знаете, что он запрограммировал. Специально SIGUSR ! Он может начать апокалипсис (это бесплатный сигнал для программиста делать все, что он хочет!). Но, если не обрабатывать ИЛИ в маловероятном случае, он будет завершен, программа завершится.

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

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

Тогда я бы предложил для этого почти глупый ответ: SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT, SIGKILL

И, наконец,

Определенно глупый длинный длинный ответ:

Не пытайтесь это делать дома.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPE и если ничего не SIGKILL, SIGKILL.

SIGUSR2 следует судить перед SIGUSR1 потому что нам лучше, если программа не обрабатывает сигнал. И гораздо более вероятно, что он будет обрабатывать SIGUSR1 если он обрабатывает только один из них.

BTW, KILL: не стоит посылать SIGKILL в процесс, как заявил другой ответ. Ну, подумайте, что происходит, когда вы отправляете команду shutdown? Он попробует только SIGTERM и SIGKILL. Почему вы так думаете? И зачем вам нужны какие-либо другие сигналы, если в самой команде shutdown используются только эти два?


Теперь, вернемся к длинному ответу, это приятный oneliner:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

Он спит в течение 30 секунд между сигналами. Зачем еще вам нужен онлайнер? ;)

Кроме того, рекомендуется: попробуйте использовать только сигналы 15 2 9 из разумного ответа.

безопасность: удалите второе echo когда вы готовы к работе. Я называю это своей dry-run для onliners. Всегда используйте его для тестирования.


Сценарий убийственно

На самом деле меня так заинтриговал этот вопрос, что я решил создать небольшой скрипт, чтобы сделать именно это. Пожалуйста, не стесняйтесь скачать (клонировать) его здесь:

GitHub ссылка на Killgracefully репозиторий

Ответ 5

  • SIGTERM эквивалентен "щелчку" X "в окне.
  • SIGTERM - это то, что Linux использует в первую очередь, когда оно закрывается.

Ответ 6

HUP звучит как мусор для меня. Я бы послал его, чтобы заставить демона перечитать его конфигурацию.

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

Подробнее об этом на Wikipedia

Ответ 7

При всем обсуждении, здесь не было предложено никакого кода. Вот мой прием:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi