In quale ordine devo inviare segnali ai processi di arresto regolare?


90

In un commento a questa risposta di un'altra domanda , il commentatore dice:

non usare kill -9 a meno che non sia assolutamente necessario! SIGKILL non può essere intercettato, quindi il programma interrotto non può eseguire alcuna routine di arresto per ad esempio cancellare i file temporanei. Prima prova HUP (1), poi INT (2), poi QUIT (3)

Sono d'accordo in linea di principio in merito SIGKILL, ma il resto è una novità per me. Dato che il segnale predefinito inviato da killè SIGTERM, mi aspetterei che sia il segnale più comunemente previsto per l'arresto regolare di un processo arbitrario. Inoltre, l'ho visto SIGHUPusato per motivi non risolutivi, come dire a un demone "rileggi il tuo file di configurazione". E mi sembra che SIGINT(la stessa interruzione che normalmente si ottiene con Ctrl-C, giusto?) Non è ampiamente supportata come dovrebbe essere, o termina in modo piuttosto sgraziato.

Dato che SIGKILLè l'ultima risorsa - Quali segnali e in quale ordine dovresti inviare a un processo arbitrario, al fine di spegnerlo il più graziosamente possibile?

Per favore comprova le tue risposte con fatti di supporto (al di là delle preferenze o opinioni personali) o riferimenti, se puoi.

Nota: sono particolarmente interessato alle migliori pratiche che includono la considerazione di bash / Cygwin.

Modifica: Finora, nessuno sembra menzionare INT o QUIT, e c'è una menzione limitata di HUP. C'è qualche motivo per includerli in un ordinato processo di uccisione?


4
Se devi ricorrere a SIGKILL per uccidere davvero un processo, lo considererei un bug nel programma.
sigjuice

Risposte:


121

SIGTERM dice a un'applicazione di terminare. Gli altri segnali comunicano all'applicazione altre cose che non sono correlate allo spegnimento, ma a volte possono avere lo stesso risultato. Non usare quelli. Se vuoi che un'applicazione si chiuda, dillo a. Non dargli segnali fuorvianti.

Alcune persone credono che il modo standard intelligente per terminare un processo sia inviargli una serie di segnali, come HUP, INT, TERM e infine KILL. Questo è ridicolo. Il segnale giusto per la terminazione è SIGTERM e se SIGTERM non termina il processo immediatamente, come potresti preferire, è perché l'applicazione ha scelto di gestire il segnale. Il che significa che ha un'ottima ragione per non terminare immediatamente: ha del lavoro di pulizia da fare. Se interrompi il lavoro di pulizia con altri segnali, non è possibile sapere quali dati dalla memoria non sono stati ancora salvati su disco, quali applicazioni client sono rimaste in sospeso o se lo stai interrompendo "a metà frase", il che è effettivamente un danneggiamento dei dati.

Per ulteriori informazioni su quale sia il vero significato dei segnali, vedere sigaction (2). Non confondere "Azione predefinita" con "Descrizione", non sono la stessa cosa.

SIGINT viene utilizzato per segnalare un "interrupt di tastiera" interattivo del processo. Alcuni programmi possono gestire la situazione in un modo speciale per gli utenti del terminale.

SIGHUP viene utilizzato per segnalare che il terminale è scomparso e non sta più guardando il processo. Questo è tutto. Alcuni processi scelgono di spegnersi in risposta, generalmente perché il loro funzionamento non ha senso senza un terminale, alcuni scelgono di fare altre cose come ricontrollare i file di configurazione.

SIGKILL viene utilizzato per rimuovere forzatamente il processo dal kernel. È speciale nel senso che non è effettivamente un segnale per il processo, ma piuttosto viene interpretato direttamente dal kernel.

Non inviare SIGKILL. SIGKILL non dovrebbe certamente mai essere inviato tramite script. Se l'applicazione gestisce SIGTERM, può volerci un secondo per ripulirlo, può richiedere un minuto, può richiedere un'ora . A seconda di ciò che l'applicazione deve essere eseguita prima che sia pronta per terminare. Qualsiasi logica che " presume " che la sequenza di pulizia di un'applicazione abbia impiegato abbastanza tempo e debba essere scorciatoia o SIGKILL dopo X secondi è semplicemente sbagliata .

L'unico motivo per cui un'applicazione avrebbe bisogno di un SIGKILL per terminare è se qualcosa si è interrotto durante la sequenza di pulizia. In tal caso è possibile aprire un terminale e SIGKILL manualmente. A parte questo, l'unico altro motivo per cui vorresti SIGKILL qualcosa è perché VUOI impedire che si pulisca da solo.

Anche se mezzo mondo invia ciecamente SIGKILL dopo 5 secondi, è ancora una cosa orribilmente sbagliata da fare.


13
Hai ragione sul fatto che ci sono molti abusi di SIGKILL là fuori. Ma c'è un tempo e un luogo per usarlo, anche da un copione. Molte, molte app intrappolano SIGTERM ed escono con grazia in meno di un secondo o entro pochi secondi, e una di queste è ancora in esecuzione 30 secondi dopo è perché è bloccata.
dwc

4
@dwc: prova a lasciarlo funzionare una volta per un'ora. Se non muore, viene "incastrato" e risolvilo, oppure sii pigro e in futuro lo SIGKILL dopo un po 'di tempo. Prendi nota che probabilmente stai corrompendo cose e ricorda che questo NON è qualcosa che dovresti fare "per impostazione predefinita".
lhunath

2
@lhunath: Spero che non ti dispiaccia, ho riorganizzato i tuoi paragrafi in modo da rendere la risposta più diretta e seguire chiaramente dalla domanda. Lo sfogo anti-SIGKILL è roba buona, ma un punto secondario. Grazie ancora per una risposta eccellente ed educativa.
sistema PAUSA

8
Non inviare SIGKILL. Mai. Semplicemente sbagliato. Veramente? Anche se il tuo sistema sta già bruciando grazie a loop infiniti. In bocca al lupo. -1
konsolebox

//, Upvoting per questo è ridicolo.
Nathan Basanese

18

Risposta breve : Invia SIGTERM, 30 secondi più tardi, SIGKILL. Cioè, invia SIGTERM, aspetta un po '(può variare da programma a programma, potresti conoscere meglio il tuo sistema, ma da 5 a 30 secondi sono sufficienti. Quando spegni una macchina, potresti vederla aspettare automaticamente fino a 1'30 s. Perché la fretta, dopo tutto?), Quindi inviare SIGKILL.

Risposta ragionevole : SIGTERM, SIGINT, SIGKILL Questo è più che sufficiente. Il processo molto probabilmente terminerà prima SIGKILL.

Lungo Risposta : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Questo non è necessario, ma almeno non stai fuorviando il processo relativo al tuo messaggio. Tutti questi segnali non significa che si desidera che il processo per fermare quello che sta facendo e uscire.

Non importa quale risposta scegli da questa spiegazione, tienilo a mente!

Se invii un segnale che significa qualcos'altro, il processo potrebbe gestirlo in modi molto diversi (da un lato). D'altra parte, se il processo non gestisce il segnale, non importa cosa invii dopotutto, il processo si chiuderà comunque (quando l'azione predefinita è terminare, ovviamente).

Quindi, devi pensare come te stesso come un programmatore. Codifichereste un gestore di funzioni per, diciamo, SIGHUPchiudere un programma che si connette a qualcosa, o lo fareste in loop per provare a connettervi di nuovo? Questa è la domanda principale qui! Ecco perché è importante inviare solo segnali che significano ciò che intendi.

Risposta lunga quasi stupida :

La tabella seguente contiene i segnali rilevanti e le azioni predefinite nel caso in cui il programma non li gestisca.

Li ho ordinati nell'ordine che suggerisco di usare (a proposito, ti consiglio di usare la risposta ragionevole , non questa qui), se hai davvero bisogno di provarli tutti (sarebbe divertente dire che la tabella è ordinata in termini di la distruzione che possono causare, ma non è completamente vero).

I segnali con un asterisco (*) NON sono consigliati. La cosa importante di questi è che potresti non sapere mai cosa è programmato per fare. Specialmente SIGUSR! Potrebbe iniziare l'apocalisse (è un segnale gratuito per un programmatore che fa quello che vuole!). Ma, se non gestito O nel caso improbabile che venga gestito per terminare, il programma terminerà.

Nella tabella, i segnali con le opzioni predefinite per terminare e generare un core dump vengono lasciati alla fine, appena prima 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

Poi vorrei suggerire per questa lunga risposta quasi stupido : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

E infine, il

Risposta decisamente lunga e lunga :

Non provarlo a casa.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEE se niente ha funzionato, SIGKILL.

SIGUSR2dovrebbe essere provato prima SIGUSR1perché è meglio se il programma non gestisce il segnale. Ed è molto più probabile che gestisca SIGUSR1se ne gestisce solo uno.

A proposito, il KILL : non è sbagliato inviare SIGKILLa un processo, come affermava un'altra risposta. Bene, pensi cosa succede quando invii un shutdowncomando? Ci proverà SIGTERMe SIGKILLsolo. Perché pensi che sia così? E perché hai bisogno di altri segnali, se il shutdowncomando stesso utilizza solo questi due?


Ora, tornando alla risposta lunga , questo è un bel oneliner:

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

Dorme per 30 secondi tra i segnali. Perché altrimenti avresti bisogno di un oneliner ? ;)

Inoltre, consigliato: provalo solo con segnali 15 2 9dalla risposta ragionevole .

sicurezza : togli la seconda echoquando sei pronto per partire. Lo chiamo mio dry-runper gli onliner . Usalo sempre per testare.


Script killgracefully

In realtà ero così incuriosito da questa domanda che ho deciso di creare una piccola sceneggiatura per fare proprio questo. Per favore, sentiti libero di scaricarlo (clonarlo) qui:

Collegamento GitHub al repository Killgracefully


8

Tipicamente invieresti SIGTERM, il valore predefinito di kill. È l'impostazione predefinita per un motivo. Dovresti ricorrere solo se un programma non si arresta in un ragionevole lasso di tempo SIGKILL. Ma si noti che con SIGKILLil programma non è possibile ripulire le cose ei dati potrebbero essere danneggiati.

Quanto a SIGHUP, HUPsta per "riagganciare" e storicamente significava che il modem si disconnetteva. È essenzialmente equivalente a SIGTERM. Il motivo per cui i daemon a volte usano SIGHUPper riavviare o ricaricare la configurazione è che i daemon si scollegano da qualsiasi terminale di controllo poiché un daemon non ne ha bisogno e quindi non li riceverebbe mai SIGHUP, quindi quel segnale è stato considerato "liberato" per uso generale. Non tutti i daemon lo usano per ricaricare! L'azione predefinita per SIGHUP è terminare e molti demoni si comportano in questo modo! Quindi non puoi andare ciecamente a inviare messaggi SIGHUPdi posta elettronica ai daemon aspettandoti che sopravvivano.

Modifica: SIGINT probabilmente è inappropriato terminare un processo, in quanto è normalmente legato ^Co qualunque sia l'impostazione del terminale per interrompere un programma. Molti programmi acquisiscono questo per i propri scopi, quindi è abbastanza comune da non funzionare. SIGQUITin genere ha l'impostazione predefinita di creare un core dump e, a meno che non si desideri disporre di file core, non è nemmeno un buon candidato.

Riepilogo: se invii SIGTERMe il programma non muore entro i tuoi tempi, invialo SIGKILL.


4
Si noti che il follow-up con SIGKILL dovrebbe essere eseguito solo in situazioni in cui lo spegnimento istantaneo è una priorità più alta rispetto alla prevenzione della perdita / danneggiamento dei dati.
thomasrutter

@dwc non ho capito il seguente punto nella tua risposta. potresti per favore aiutare "Il motivo per cui i daemon a volte usano SIGHUP per riavviare o ricaricare la configurazione è che i daemon si staccano da qualsiasi terminale di controllo e quindi non riceveranno mai SIGTERM, quindi quel segnale è stato considerato" liberato "per uso generale."
Jack

3
@Jack Fammi provare: SIGHUP è il segnale di "riaggancio" che dice a un processo che il terminale è stato disconnesso. Poiché i daemon vengono eseguiti in background, non hanno bisogno di terminali. Ciò significa che un segnale di "riaggancio" non è rilevante per i daemon. Non lo riceveranno mai da una disconnessione del terminale, poiché non hanno terminali collegati in primo luogo. E poiché il segnale è comunque definito, sebbene non ne abbiano bisogno per lo scopo originale, molti demoni lo usano invece per uno scopo diverso, come rileggere i propri file di configurazione.
sistema PAUSA

Grazie sistema PAUSA. questo è utile.
Jack

7

SIGTERMin realtà significa inviare a un'applicazione un messaggio: " saresti così gentile e ti suiciderei ". Può essere intercettato e gestito dall'applicazione per eseguire la pulizia e il codice di arresto.

SIGKILLnon può essere intrappolato dall'applicazione. L'applicazione viene interrotta dal sistema operativo senza alcuna possibilità di pulizia.

È tipico inviare SIGTERMprima, dormire un po 'di tempo, quindi inviare SIGKILL.


Suppongo che i sondaggi sarebbero un po 'più efficienti che dormire (prima del SIGKILL)
Ohad Schneider

@OhadSchneider lo sarebbe, ma ciò richiederebbe qualcosa di più del semplice comando bash.
vartec

Sì, immagino che dovresti eseguire il ciclo mentre il processo è ancora attivo usando qualcosa del genere: stackoverflow.com/a/15774758/67824 .
Ohad Schneider

5
  • SIGTERM equivale a "fare clic sulla" X "" in una finestra.
  • SIGTERM è ciò che Linux usa per primo, quando si sta spegnendo.

Questo è quello che volevo sapere. +1. Grazie.
Luc

6
"SIGTERM equivale a" fare clic sulla "X" "in una finestra" No, non lo è, perché qualsiasi applicazione può facilmente aprire un numero qualsiasi di finestre (documenti e strumenti, ad esempio), figuriamoci finestre di dialogo, e potrebbe non risponde anche a un comando di chiusura dell'ultima finestra come fa a un comando di uscita (non riesco a pensare a nessun esempio ovvio, ma sebbene non ovvio, non c'è motivo per cui non possa essere fatto in questo modo). SIGTERM è (o dovrebbe essere) equivalente alla normale richiesta di chiusura dell'applicazione, tuttavia ciò potrebbe essere eseguito in quella particolare applicazione .
utente

3

Con tutta la discussione in corso qui, nessun codice è stato offerto. Ecco la mia opinione:

#!/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 suona come una spazzatura per me. Lo invierei per ottenere un demone per rileggere la sua configurazione.

SIGTERM può essere intercettato; i tuoi demoni potrebbero avere un codice di pulizia da eseguire quando riceve quel segnale. Non puoi farlo per SIGKILL. Quindi con SIGKILL non stai dando alcuna opzione all'autore del demone.

Altro su questo su Wikipedia

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.