У якому порядку слід надсилати сигнали до процесів витонченого вимкнення?


89

У коментарі до цієї відповіді на інше питання коментатор зазначає:

не використовуйте kill -9, якщо це абсолютно не потрібно! SIGKILL не може бути перехоплений, тому вбита програма не може запустити жодну процедуру вимкнення, наприклад, для стирання тимчасових файлів. Спочатку спробуйте HUP (1), потім INT (2), потім КВІТ (3)

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

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

Будь ласка, обґрунтуйте свої відповіді підтверджуючими фактами (крім особистих уподобань чи думок) або посиланнями, якщо можете.

Примітка: Мене особливо цікавлять найкращі практики, які включають розгляд питань bash / Cygwin.

Редагувати: Поки що, здається, ніхто не згадує INT або QUIT, а про HUP згадується обмежено. Чи є якісь причини включати їх до впорядкованого процесу вбивства?


4
Якщо вам доведеться вдатися до SIGKILL, щоб справді вбити процес, я вважав би це помилкою в програмі.
sigjuice

Відповіді:


115

SIGTERM повідомляє програму про припинення дії. Інші сигнали повідомляють додатку про інші речі, які не пов’язані з вимкненням, але іноді можуть мати однакові результати. Не використовуйте їх. Якщо ви хочете, щоб програма закрилася, скажіть це. Не подавайте йому оманливих сигналів.

Деякі люди вважають, що розумним стандартним способом завершення процесу є надсилання йому безлічі сигналів, таких як HUP, INT, TERM і, нарешті, KILL. Це смішно. Правильним сигналом для припинення є SIGTERM, і якщо SIGTERM не завершить процес миттєво, як ви могли б вважати за краще, це тому, що програма обрала обробку сигналу. Що означає, що у нього є дуже вагома причина не негайно припиняти роботу: її чекає робота з очищення. Якщо ви перериваєте цю роботу з очищенням з іншими сигналами, не можна сказати, які дані з пам'яті вони ще не зберегли на диск, які клієнтські програми залишаються зависатими чи ви перериваєте їх "в середині речення", що фактично є пошкодженням даних.

Для отримання додаткової інформації про те, що справжнє значення сигналів, див. Розподіл (2). Не плутайте "Дію за замовчуванням" з "Опис", це не одне і те ж.

SIGINT використовується для сигналізації інтерактивного "переривання клавіатури" процесу. Деякі програми можуть вирішувати ситуацію спеціально для цілей користувачів терміналів.

SIGHUP використовується, щоб сигналізувати про те, що термінал зник і більше не дивиться на процес. Це все. Деякі процеси вирішують закрити у відповідь, як правило, оскільки їх робота не має сенсу без терміналу, деякі вирішують робити інші дії, наприклад, перевіряти конфігураційні файли.

SIGKILL використовується для примусового видалення процесу з ядра. Особливо в тому сенсі, що насправді це не сигнал до процесу, а навпаки, інтерпретується ядром безпосередньо.

Не надсилайте SIGKILL. SIGKILL, звичайно, ніколи не повинен надсилатися сценаріями. Якщо програма обробляє SIGTERM, це може зайняти секунду для очищення, це може зайняти хвилину, це може зайняти годину . Залежно від того, яку програму потрібно виконати, перш ніж вона буде готова до завершення. Будь-яка логіка, яка " припускає " послідовність очищення програми, зайняла досить багато часу, і її потрібно скоротити або SIGKILLed через X секунд, просто невірно .

Єдина причина, чому додатку потрібен SIGKILL для завершення, - це те, що щось вислуховувалося під час послідовності очищення. У цьому випадку ви можете відкрити термінал і SIGKILL вручну. Окрім цього, єдина ще одна причина, через яку ви б SIGKILL щось зробили, полягає в тому, що ви ХОЧЕТЕ запобігти самоочищенню.

Незважаючи на те, що половина світу наосліп надсилає SIGKILL через 5 секунд, все одно це жахливо неправильно робити.


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

4
@dwc: Спробуйте дозволити їй працювати раз на годину. Якщо воно не вмирає, тоді воно "вклинюється" і або виправляє, або лінується, і в майбутньому SIGKILL це через деякий час. Зверніть увагу, що ви, мабуть, псуєте речі і пам’ятайте, що це НЕ те, що ви повинні робити "за замовчуванням".
люнат

2
@lhunath: Сподіваюся, ви не проти, я переставив ваші абзаци, щоб відповідь стала більш прямою і чітко випливала з питання. Виступ проти SIGKILL - хороший матеріал, але другорядний момент. Ще раз спасибі за чудову та освітню відповідь.
система ПАУЗА

8
Не надсилайте SIGKILL. Ніколи. Просто невірно. Справді? Навіть якщо ваша система вже горить завдяки нескінченним циклам. Удачі. -1
konsolebox

//, Голосувати за це смішно.
Натан Басанес

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 секунд між сигналами. Навіщо ще вам потрібен oneliner ? ;)

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

безпека : зніміть другу, echoколи будете готові до роботи. Я називаю це своїм dry-runдля онлайнерів . Завжди використовуйте його для тестування.


Сценарій вдячно вбив

Насправді мене це питання настільки заінтригувало, що я вирішив створити невеликий сценарій для цього. Будь ласка, не соромтеся завантажувати (клонувати) його тут:

Посилання 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 - це сигнал "повісити трубку", який повідомляє процес, що термінал відключений. Оскільки демони працюють у фоновому режимі, їм не потрібні термінали. Це означає, що сигнал "покласти трубку" не має відношення до демонів. Вони ніколи не отримають його від роз'єднання терміналу, оскільки спочатку у них немає підключених терміналів. І оскільки сигнал у будь-якому випадку визначений, хоча він їм і не потрібний для початкової мети, багато демонів використовують його замість цього з іншою метою, наприклад, для перечитування своїх конфігураційних файлів.
система ПАУЗА

Подячна система ПАУЗА. це корисно.
Джек

7

SIGTERMнасправді означає надсилання заявки повідомлення: " чи не могли б ви бути таким добрим і покінчити життя самогубством ". Його можна затримати та обробити додатком для запуску коду очищення та вимкнення.

SIGKILLне може бути захоплений програмою. Програму вбиває ОС без жодних шансів на очищення.

Типово спочатку відправити SIGTERM, трохи поспати, а потім відправити SIGKILL.


Я думаю, опитування було б трохи ефективнішим, ніж спати (до SIGKILL)
Охад Шнайдер,

@OhadSchneider це було б, але для цього знадобиться щось більше, ніж проста команда bash.
vartec

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

5
  • SIGTERM еквівалентно "натисканню" X "у вікні.
  • SIGTERM - це те, що спочатку використовує Linux, коли він вимикається.

Це те, що я хотів знати. +1. Дякую.
Luc

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.