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

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

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

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

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

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

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

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

7 ответов

Решение

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

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

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

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

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

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

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

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

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

Краткий ответ: Отправить SIGTERM 30 секунд спустя SIGKILL, То есть отправить SIGTERM, подождите немного (это может варьироваться от программы к программе, вы, возможно, знаете свою систему лучше, но достаточно 5–30 секунд. При выключении машины вы можете увидеть, что она автоматически ждет до 13: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 секунд между сигналами. Зачем еще вам нужен oneliner?;)

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

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


Скрипт убивает грациозно

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

GitHub ссылка на хранилище Killgracefully

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

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

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

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

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

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

Это типично для отправки SIGTERM сначала поспи немного, потом пошли SIGKILL,

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

#!/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
  • SIGTERM эквивалентно "нажатию на" X "" в окне.
  • SIGTERM - это то, что Linux использует в первую очередь, когда он выключается.

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

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

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

Другие вопросы по тегам