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


88

В комментарии к этому ответу на другой вопрос комментатор говорит:

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

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

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

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

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

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


4
Если вам нужно прибегнуть к SIGKILL, чтобы действительно убить процесс, я бы счел это ошибкой в ​​программе.
sigjuice

Ответы:


114

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

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

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

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

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

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

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

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

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


13
Вы правы в том, что SIGKILL часто используют не по назначению. Но есть время и место для его использования, даже из сценария. Многие, многие приложения перехватывают SIGTERM и корректно завершают работу менее чем за секунду или всего за несколько секунд, и одно из них все еще работает 30 секунд спустя, потому что оно заклинило.
dwc,

4
@dwc: Дайте ему поработать один раз в час. Если он не умирает, то он "заклинивает" и либо исправляет, либо поленился и в будущем SIGKILL это через некоторое время. Обратите внимание, что вы, вероятно, портите что-то, и помните, что это НЕ то, что вы должны делать «по умолчанию».
lhunath

2
@lhunath: Надеюсь, вы не против, я переставил ваши абзацы, чтобы сделать ответ более прямым и ясным, исходя из вопроса. Рассуждения против SIGKILL - это хорошо, но второстепенный момент. Еще раз спасибо за отличный и познавательный ответ.
система ПАУЗА

8
Не отправляйте SIGKILL. Когда-либо. Совершенно неправильно. В самом деле? Даже если ваша система уже горит благодаря бесконечным циклам. Удачи. -1
konsolebox

// Голосовать за это просто смешно.
Nathan Basanese

17

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

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

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

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

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

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

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

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

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

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

Сигналы со звездочкой (*) НЕ рекомендуются. В них важно то, что вы никогда не узнаете, на что они запрограммированы. Специально 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.

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

Кстати, УБИЙСТВО : отправить SIGKILLв процесс - это нормально, как сказано в другом ответе. Ну подумайте, а что будет при отправке shutdownкоманды? Будет стараться SIGTERMи SIGKILLтолько. Как вы думаете, почему это так? А зачем вообще нужны другие сигналы, если сама shutdownкоманда использует только эти два?


Теперь, возвращаясь к длинному ответу , это хорошая единственная строка:

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для онлайн-пользователей . Всегда используйте его для тестирования.


Скрипт killgracefully

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

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


8

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

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

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

Резюме: если вы отправляете, SIGTERMа программа не умирает в установленные сроки, отправьте ее SIGKILL.


4
Обратите внимание, что после этого с помощью SIGKILL следует выполнять только ситуации, когда немедленное выключение является более высоким приоритетом, чем предотвращение потери / повреждения данных.
thomasrutter

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

3
@Jack Позвольте мне попробовать: SIGHUP - это сигнал "положить трубку", который сообщает процессу, что терминал отключился. Поскольку демоны работают в фоновом режиме, им не нужны терминалы. Это означает, что сигнал «положить трубку» не имеет отношения к демонам. Они никогда не получат его из-за отключения терминала, поскольку у них вообще нет подключенных терминалов. И поскольку сигнал все равно определен, хотя он им не нужен для первоначальной цели, многие демоны используют его вместо этого для другой цели, например, для повторного чтения своих файлов конфигурации.
система ПАУЗА

Спасибо системе PAUSE. это полезно.
Джек

6

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

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

Обычно SIGTERMсначала отправить , поспать, потом отправить SIGKILL.


Полагаю, опрос был бы немного эффективнее, чем сон (до SIGKILL)
Охад Шнайдер

@OhadSchneider, но для этого потребуется нечто большее, чем простая команда bash.
Vartec

Да, я думаю, вам нужно будет выполнить цикл, пока процесс еще жив, используя что-то вроде этого: stackoverflow.com/a/15774758/67824 .
Охад Шнайдер

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

Это то, что я хотел знать. +1. Спасибо.
Люк

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

3

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

#!/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

0

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

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

Подробнее об этом в Википедии

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.