W jakiej kolejności powinienem wysyłać sygnały do ​​bezpiecznego zamykania procesów?


88

W komentarzu do tej odpowiedzi na inne pytanie komentator mówi:

nie używaj kill -9, chyba że jest to absolutnie konieczne! SIGKILL nie może zostać uwięziony, więc zabity program nie może uruchomić żadnych procedur zamykania systemu, aby np. Usunąć pliki tymczasowe. Najpierw spróbuj HUP (1), potem INT (2), a następnie QUIT (3)

W zasadzie się zgadzam SIGKILL, ale reszta to dla mnie nowość. Biorąc pod uwagę, że domyślnym sygnałem wysyłanym przez killjest SIGTERM, spodziewam się, że jest to najczęściej oczekiwany sygnał do płynnego zamknięcia dowolnego procesu. Widziałem również, że jest to SIGHUPużywane z powodów nie kończących, takich jak nakazanie demonowi „ponownego odczytania pliku konfiguracyjnego”. I wydaje mi się, że SIGINT(to samo przerwanie, które zwykle otrzymujesz za pomocą Ctrl-C, prawda?) Nie jest tak szeroko obsługiwane, jak powinno, lub kończy się raczej niezręcznie.

Biorąc pod uwagę, że SIGKILLjest to ostatnia deska ratunku - jakie sygnały iw jakiej kolejności należy wysłać do dowolnego procesu, aby zamknąć go tak wdzięcznie, jak to możliwe?

W miarę możliwości prosimy uzasadniać swoje odpowiedzi faktami pomocniczymi (poza osobistymi preferencjami lub opiniami) lub odniesieniami.

Uwaga: jestem szczególnie zainteresowany najlepszymi praktykami, które obejmują rozważenie bash / Cygwin.

Edycja: Jak dotąd nikt nie wspomina o INT lub QUIT, a wzmianka o HUP jest ograniczona. Czy jest jakiś powód, aby uwzględnić je w uporządkowanym procesie zabijania?


4
Jeśli musisz użyć SIGKILL, aby naprawdę zabić proces, uznałbym to za błąd w programie.
sigjuice

Odpowiedzi:


114

SIGTERM nakazuje aplikacji zakończenie. Inne sygnały informują aplikację o innych rzeczach, które nie są związane z zamknięciem, ale czasami mogą mieć ten sam skutek. Nie używaj ich. Jeśli chcesz, aby aplikacja została zamknięta, powiedz jej. Nie dawaj mu mylących sygnałów.

Niektórzy uważają, że sprytnym standardowym sposobem zakończenia procesu jest wysłanie do niego szeregu sygnałów, takich jak HUP, INT, TERM i wreszcie KILL. To jest niedorzeczne. Odpowiednim sygnałem do zakończenia jest SIGTERM i jeśli SIGTERM nie kończy procesu natychmiast, jak byś wolał, to dlatego, że aplikacja zdecydowała się obsłużyć ten sygnał. Co oznacza, że ​​ma bardzo dobry powód, aby nie przerywać natychmiast: ma do zrobienia porządek. Jeśli przerwiesz pracę czyszczenia innymi sygnałami, nie wiadomo, jakie dane z pamięci nie zostały jeszcze zapisane na dysku, jakie aplikacje klienckie pozostały zawieszone lub czy przerywasz je „w połowie zdania”, co w praktyce oznacza uszkodzenie danych.

Aby uzyskać więcej informacji na temat prawdziwego znaczenia sygnałów, zobacz sigaction (2). Nie myl „Działania domyślnego” z „Opisem”, to nie to samo.

SIGINT jest używany do sygnalizowania interaktywnego „przerwania klawiatury” procesu. Niektóre programy mogą obsłużyć sytuację w specjalny sposób na potrzeby użytkowników terminala.

SIGHUP jest używany do sygnalizowania, że ​​terminal zniknął i nie patrzy już na proces. To wszystko. Niektóre procesy decydują się na zamknięcie w odpowiedzi, na ogół dlatego, że ich działanie nie ma sensu bez terminala, a niektóre decydują się na inne czynności, takie jak ponowne sprawdzenie plików konfiguracyjnych.

SIGKILL służy do wymuszonego usuwania procesu z jądra. Jest wyjątkowy w tym sensie, że w rzeczywistości nie jest sygnałem dla procesu, ale jest bezpośrednio interpretowany przez jądro.

Nie wysyłaj SIGKILLA. SIGKILL z pewnością nigdy nie powinien być wysyłany przez skrypty. Jeśli aplikacja obsługuje SIGTERM, czyszczenie może zająć sekundę, minutę, a nawet godzinę . W zależności od tego, co aplikacja ma zrobić, zanim będzie gotowa do zakończenia. Każda logika, która „ zakłada ”, że sekwencja czyszczenia aplikacji zajęła wystarczająco dużo czasu i wymaga skrótu lub SIGKILL po X sekundach, jest po prostu błędna .

Jedynym powodem, dla którego aplikacja będzie potrzebować do SIGKILL do wypowiedzenia, jeśli coś jest na podsłuchu podczas jego sekwencji czyszczenia. W takim przypadku możesz otworzyć terminal i SIGKILL go ręcznie. Poza tym, jedynym innym powodem, dla którego chciałbyś coś ZABIĆ, jest to, że CHCESZ zapobiec samoczynnemu oczyszczeniu.

Chociaż połowa świata na ślepo wysyła SIGKILL po 5 sekundach, nadal jest to strasznie złe.


13
Masz rację, że istnieje wiele nadużyć SIGKILL. Ale jest czas i miejsce, aby to wykorzystać, nawet ze scenariusza. Wiele, wiele aplikacji przechwytuje SIGTERM i wychodzi z wdziękiem w mniej niż sekundę lub w ciągu zaledwie kilku sekund, a jedna z nich nadal działa 30 sekund później, ponieważ jest zaklinowana.
dwc

4
@dwc: Spróbuj uruchomić go raz na godzinę. Jeśli nie umrze, to jest „zaklinowany” i albo napraw go, albo bądź leniwy iw przyszłości SIGKILL to po pewnym czasie. Zwróć uwagę , że prawdopodobnie psujesz rzeczy i pamiętaj, że NIE jest to coś, co powinieneś robić „domyślnie”.
lhunath

2
@lhunath: Mam nadzieję, że nie masz nic przeciwko, uporządkowałem Twoje akapity, aby odpowiedź była bardziej bezpośrednia i jasno wynikała z pytania. Rant anty-SIGKILL jest dobry, ale kwestia drugorzędna. Jeszcze raz dziękuję za doskonałą i edukacyjną odpowiedź.
system PAUSE

8
Nie wysyłaj SIGKILLA. Zawsze. Po prostu źle. Naprawdę? Nawet jeśli Twój system już się pali dzięki nieskończonym pętlom. Powodzenia. -1
konsolebox

//, Głosowanie za tym jest śmieszne.
Nathan Basanese

17

Krótka odpowiedź : Wyślij SIGTERM, 30 sekund później SIGKILL. To znaczy, wyślij SIGTERM, poczekaj trochę (może się to różnić w zależności od programu, możesz lepiej poznać swój system, ale wystarczy 5 do 30 sekund. Podczas wyłączania maszyny możesz zobaczyć, że automatycznie czeka do 1'30 s. Po co się w końcu spieszyć?), A potem wysłać SIGKILL.

Rozsądna odpowiedź : SIGTERM, SIGINT, SIGKILL To jest więcej niż wystarczająco. Proces ten będzie bardzo prawdopodobnie zakończyć przed SIGKILL.

Długa odpowiedź : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Nie jest to konieczne, ale przynajmniej nie wprowadzasz w błąd procesu dotyczącego wiadomości. Wszystkie te sygnały nie znaczy, że chcą, aby zatrzymać proces, co robi i wyjść.

Bez względu na to, jaką odpowiedź wybierzesz z tego wyjaśnienia, miej to na uwadze!

Jeśli wyślesz sygnał, który oznacza coś innego, proces może obsłużyć to na bardzo różne sposoby (z jednej strony). Z drugiej strony, jeśli proces nie obsłuży sygnału, nie ma znaczenia, co wyślesz, mimo wszystko proces zakończy się (jeśli domyślną akcją jest oczywiście zakończenie).

Musisz więc myśleć jak programista. Czy zakodowałbyś program obsługi funkcji, aby, powiedzmy, SIGHUPzamknąć program, który się z czymś łączy, czy też zapętliłbyś go, aby spróbować połączyć się ponownie? Oto główne pytanie! Dlatego ważne jest, aby po prostu wysyłać sygnały, które oznaczają to, co zamierzasz.

Prawie głupia długa odpowiedź :

Poniższa tabela zawiera odpowiednie sygnały i domyślne działania na wypadek, gdyby program ich nie obsłużył.

Zamówiłem je w kolejności, w której proponuję użyć (przy okazji proponuję użyć rozsądnej odpowiedzi , nie tej tutaj), jeśli naprawdę potrzebujesz wypróbować je wszystkie (fajnie byłoby powiedzieć, że stół jest uporządkowany pod względem zniszczenia, jakie mogą spowodować, ale tak nie jest końca prawdą).

Sygnały oznaczone gwiazdką (*) NIE są zalecane. Ważną rzeczą jest to, że możesz nigdy nie wiedzieć, do czego jest zaprogramowany. Specjalnie SIGUSR! Może rozpocząć apokalipsę (jest to darmowy sygnał dla programisty, który robi, co chce!). Ale jeśli nie jest obsługiwane LUB w mało prawdopodobnym przypadku zakończenia, program zakończy działanie.

W tabeli sygnały z domyślnymi opcjami zakończenia i generowania zrzutu pamięci są pozostawione na końcu, tuż przed 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

Następnie chciałbym zaproponować w tym prawie głupiego długa odpowiedź : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

I wreszcie

Zdecydowanie głupia długa odpowiedź :

Nie próbuj tego w domu.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEI jeśli nic nie działało, SIGKILL.

SIGUSR2powinien być wypróbowany wcześniej, SIGUSR1ponieważ lepiej będzie, jeśli program nie obsługuje sygnału. I jest dużo bardziej prawdopodobne, że poradzi sobie z tym, SIGUSR1jeśli obsługuje tylko jedną z nich.

BTW, KILL : wysyłanie SIGKILLdo procesu nie jest złe , jak stwierdziła inna odpowiedź. Zastanów się, co się stanie, gdy wyślesz shutdownpolecenie? Spróbuje SIGTERMi SIGKILLtylko. Jak myślisz, dlaczego tak jest? A dlaczego potrzebujesz innych sygnałów, skoro sama shutdownkomenda używa tylko tych dwóch?


Wracając do długiej odpowiedzi , oto fajny oneliner:

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

Śpi przez 30 sekund między sygnałami. Po co jeszcze miałbyś potrzebować onelinera ? ;)

Zalecane również: wypróbuj tylko sygnały 15 2 9z rozsądnej odpowiedzi .

bezpieczeństwo : zdejmij drugą, echogdy jesteś gotowy do pracy. Nazywam to moim dry-rundla onlinerów . Zawsze używaj go do testowania.


Skrypt zabija z wdziękiem

Właściwie to tak mnie zaintrygowało to pytanie, że postanowiłem stworzyć mały skrypt, aby to zrobić. Zapraszam do pobrania (sklonowania) go tutaj:

Łącze GitHub do repozytorium Killgracefully


8

Zazwyczaj wysyłasz SIGTERM, domyślnie kill. Nie bez powodu jest to ustawienie domyślne. Tylko wtedy, gdy program nie zamyka się w rozsądnym czasie, należy się do tego uciec SIGKILL. Ale zauważ to w przypadkuSIGKILL program nie ma możliwości wyczyszczenia rzeczy, a dane mogą zostać uszkodzone.

Jeśli chodzi o SIGHUP, HUPoznacza "zawieszanie się" i historycznie oznaczało, że modem się rozłączył. Zasadniczo jest to odpowiednik SIGTERM. Powodem, dla którego demony czasami używają SIGHUPdo restartowania lub przeładowywania konfiguracji, jest to, że demony odłączają się od terminali kontrolujących, ponieważ demon ich nie potrzebuje, a zatem nigdy nie odbiera SIGHUP, więc sygnał został uznany za „zwolniony” do ogólnego użytku. Nie wszystkie demony używają tego do przeładowania! Domyślną akcją dla SIGHUP jest zakończenie działania i wiele demonów zachowuje się w ten sposób! Więc nie możesz iść na ślepo, wysyłając wiadomości SIGHUPdo demonów i oczekując, że przeżyją.

Edycja: SIGINT prawdopodobnie niewłaściwe jest kończenie procesu, ponieważ normalnie jest ono powiązane z ^Club jakimkolwiek ustawieniem terminala, aby przerwać program. Wiele programów przechwytuje to do własnych celów, więc jest to na tyle powszechne, że nie działa. SIGQUITzazwyczaj ma domyślne ustawienie tworzenia zrzutu pamięci, i jeśli nie chcesz, aby pliki podstawowe były w pobliżu, to również nie jest dobrym kandydatem.

Podsumowanie: jeśli wyślesz, SIGTERMa program nie umrze w Twoim czasie, wyślij go SIGKILL.


4
Należy pamiętać, że śledzenie tego za pomocą SIGKILL powinno być wykonywane tylko w sytuacjach, w których natychmiastowe zamknięcie ma wyższy priorytet niż zapobieganie utracie / uszkodzeniu danych.
thomasrutter

@dwc Nie zrozumiałem następującego punktu Twojej odpowiedzi. czy mógłbyś pomóc "Powodem, dla którego demony czasami używają SIGHUP do restartowania lub przeładowywania konfiguracji jest to, że demony odłączają się od terminali kontrolujących i dlatego nigdy nie otrzymają SIGTERM, więc ten sygnał był uważany za" zwolniony "do ogólnego użytku."
Jack,

3
@Jack Spróbuję: SIGHUP to sygnał „rozłączenia”, który informuje proces, że terminal został odłączony. Ponieważ demony działają w tle, nie potrzebują terminali. Oznacza to, że sygnał „rozłącz się” nie dotyczy demonów. Nigdy nie otrzymają go po rozłączeniu terminala, ponieważ w pierwszej kolejności nie mają podłączonych terminali. A ponieważ sygnał i tak jest zdefiniowany, chociaż nie potrzebują go do pierwotnego celu, wiele demonów używa go zamiast tego do innego celu, takiego jak ponowne odczytanie plików konfiguracyjnych.
system PAUZA

Dzięki systemowi PAUSE. to jest pomocne.
Jack,

6

SIGTERMw rzeczywistości oznacza wysłanie do aplikacji wiadomości: „ czy byłbyś tak miły i popełnił samobójstwo ”. Może być przechwytywany i obsługiwany przez aplikację w celu uruchomienia kodu czyszczenia i zamykania.

SIGKILLnie może zostać przechwycony przez aplikację. Aplikacja zostaje zabita przez system operacyjny bez szans na wyczyszczenie.

Zazwyczaj wysyła się SIGTERMnajpierw, prześpi trochę, a potem wyśle SIGKILL.


Przypuszczam, że sondowanie byłoby nieco bardziej wydajne niż spanie (przed SIGKILL)
Ohad Schneider

@OhadSchneider tak, ale wymagałoby to czegoś więcej niż zwykłego polecenia bash.
vartec

Tak, myślę, że musisz zapętlić, gdy proces nadal działa, używając czegoś takiego: stackoverflow.com/a/15774758/67824 .
Ohad Schneider

5
  • SIGTERM jest równoważne z „kliknięciem„ X ”” w oknie.
  • SIGTERM jest tym, czego Linux używa jako pierwszy, kiedy się wyłącza.

To właśnie chciałem wiedzieć. +1. Dzięki.
Luc,

6
"SIGTERM jest równoznaczne z" kliknięciem "X" w oknie " Nie, nie jest, ponieważ każda aplikacja może z łatwością otworzyć dowolną liczbę okien (na przykład dokumentów i narzędzi), nie mówiąc już o oknach dialogowych. nawet odpowiadać na ostatnie polecenie zamknięcia okna, tak jak na polecenie wyjścia (nie przychodzą mi do głowy żadne oczywiste przykłady, ale chociaż nie jest to oczywiste, nie ma powodu, dla którego nie można tego zrobić w ten sposób). SIGTERM jest (lub powinno być) równoważne z wdzięcznym żądaniem zakończenia działania aplikacji, jednak może to zostać wykonane w tej konkretnej aplikacji .
użytkownik

3

Podczas całej dyskusji w tym miejscu nie zaoferowano żadnego kodu. Oto moja opinia:

#!/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 brzmi dla mnie jak śmieć. Wysłałbym go, aby uzyskać demona do ponownego odczytania jego konfiguracji.

SIGTERM można przechwycić; Twoje demony mogą po prostu mieć kod czyszczący do uruchomienia, gdy otrzymają ten sygnał. Nie możesz tego zrobić dla SIGKILL. Dlatego z SIGKILL nie dajesz autorowi demona żadnych opcji.

Więcej na ten temat w Wikipedii

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.