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

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

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

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

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

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

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

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


person system PAUSE    schedule 27.03.2009    source источник
comment
Если вам нужно прибегнуть к SIGKILL, чтобы действительно убить процесс, я считаю это ошибкой в ​​программе.   -  person sigjuice    schedule 27.03.2009


Ответы (7)


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

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

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

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

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

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

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

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

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

person lhunath    schedule 27.03.2009
comment
Вы правы в том, что SIGKILL часто используют не по назначению. Но есть время и место, чтобы использовать это, даже из сценария. Многие, многие приложения перехватывают SIGTERM и изящно завершают работу менее чем за секунду или всего за несколько секунд, и одно из них все еще работает 30 секунд спустя, потому что оно заклинило. - person dwc; 28.03.2009
comment
@dwc: Дайте ему поработать один раз в час. Если он не умирает, то его заклинивают и либо исправляют, либо ленитесь и в будущем SIGKILL через некоторое время. Обратите внимание, что вы, вероятно, что-то портите, и помните, что это НЕ то, что вам следует делать по умолчанию. - person lhunath; 28.03.2009
comment
@lhunath: Надеюсь, вы не против, я переставил ваши абзацы, чтобы сделать ответ более прямым и ясным, исходя из вопроса. Рассуждения против SIGKILL - это хорошо, но это второстепенный момент. Еще раз спасибо за отличный и познавательный ответ. - person system PAUSE; 01.10.2009
comment
Не отправляйте SIGKILL. Всегда. Совершенно неправильно. Правда? Даже если ваша система уже горит благодаря бесконечным циклам. Удачи. -1 - person konsolebox; 14.07.2014

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


Скрипт убивает изящно

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

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

person DrBeco    schedule 08.06.2016
comment
Мне всегда было интересно, почему действие по умолчанию для SIGUSRx - прекратить. Если программа посылает этот сигнал, это потому, что она хочет, чтобы цель сделала что-то конкретное. Если цель на самом деле не запрограммирована на что-либо, когда она получает этот сигнал, тогда, конечно, она не сможет сделать то, что намеревается процессом, который отправил сигнал, но как это означает, что желательно, чтобы процесс немедленно завершился ? Это похоже на разработку ОС, которая немедленно выключает компьютер, если он получает данные с USB-устройства, для которого нет драйвера. - person flarn2006; 24.04.2021
comment
Зачем вам вообще отправлять SIGPIPE, если это не канал, как предлагается в почти глупом длинном ответе? - person Bjorn; 16.06.2021
comment
Я уверен, что вы уже внимательно его прочитали, это НЕ рекомендуется, но оно предназначено только для отображения списка возможных заказов. Но опять же, не рекомендуется. - person DrBeco; 18.06.2021

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

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

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

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

person dwc    schedule 27.03.2009
comment
Обратите внимание, что после этого с помощью SIGKILL следует выполнять только ситуации, когда немедленное завершение работы является более высоким приоритетом, чем предотвращение потери / повреждения данных. - person thomasrutter; 28.02.2013
comment
@dwc Я не понял следующего пункта вашего ответа. Не могли бы вы помочь? Причина, по которой демоны иногда используют SIGHUP для перезапуска или перезагрузки конфигурации, заключается в том, что демоны отсоединяются от любых управляющих терминалов и, следовательно, никогда не получают SIGTERM, поэтому этот сигнал считался освобожденным для общего использования. - person Jack; 05.07.2013
comment
@Jack Позвольте мне попробовать: SIGHUP - это сигнал зависания, который сообщает процессу, что терминал отключился. Поскольку демоны работают в фоновом режиме, им не нужны терминалы. Это означает, что сигнал отбоя не имеет отношения к демонам. Они никогда не получат его при отключении терминала, поскольку у них вообще нет подключенных терминалов. И поскольку сигнал все равно определен, хотя он им не нужен для первоначальной цели, многие демоны используют его вместо этого для другой цели, например, для повторного чтения своих файлов конфигурации. - person system PAUSE; 10.07.2013
comment
Спасибо системе PAUSE. это полезно. - person Jack; 11.07.2013
comment
Re: SIGINT, вероятно, уместен, у меня есть процесс (не мой, с закрытым исходным кодом и т.д.), который постоянно не отвечает на SIGTERM, но отвечает на SIGINT. Я решил использовать SIGINT в моем скрипте, потому что это казалось безопаснее, чем прибегать к SIGKILL. Это не так? - person Wowfunhappy; 23.01.2021

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

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

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

person vartec    schedule 27.03.2009
comment
Полагаю, опрос был бы немного более эффективным, чем сон (до SIGKILL) - person Ohad Schneider; 26.01.2017
comment
@OhadSchneider, но для этого потребуется нечто большее, чем простая команда bash. - person vartec; 26.01.2017
comment
Да, я думаю, вам нужно будет выполнить цикл, пока процесс еще жив, используя что-то вроде этого: stackoverflow.com/a/15774758/67824. - person Ohad Schneider; 26.01.2017

  • SIGTERM эквивалентен "щелчку" X "в окне.
  • SIGTERM - это то, что Linux использует в первую очередь при завершении работы.
person gbarry    schedule 27.03.2009
comment
Вот что я хотел знать. +1. Спасибо. - person Luc; 02.07.2013
comment
SIGTERM эквивалентно нажатию на 'X' в окне Нет, это не так, потому что любое приложение может легко открыть любое количество окон (например, документа и инструмента), не говоря уже о диалоговых окнах и он может даже не реагировать на последнюю команду закрытия окна, как на команду выхода (я не могу придумать никаких очевидных примеров, но, хотя это и неочевидно, нет причин, по которым это нельзя сделать таким образом). SIGTERM эквивалентен (или должен быть) эквивалентен изящному запросу приложения о завершении, однако это может быть выполнено в этом конкретном приложении. - person user; 16.09.2013

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

#!/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
person Ohad Schneider    schedule 26.01.2017

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

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

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

person innaM    schedule 27.03.2009