In welcher Reihenfolge soll ich Signale an ordnungsgemäß heruntergefahrene Prozesse senden?

86

In einem Kommentar zu dieser Antwort auf eine andere Frage sagt der Kommentator:

Verwenden Sie kill -9 nur, wenn dies unbedingt erforderlich ist! SIGKILL kann nicht abgefangen werden, sodass das getötete Programm keine Routinen zum Herunterfahren ausführen kann, um beispielsweise temporäre Dateien zu löschen. Versuchen Sie zuerst HUP (1), dann INT (2) und dann QUIT (3).

Ich stimme im Prinzip zu SIGKILL, aber der Rest ist neu für mich. Angesichts der Tatsache, dass das von gesendete Standardsignal killist SIGTERM, würde ich erwarten, dass es das am häufigsten erwartete Signal für das ordnungsgemäße Herunterfahren eines beliebigen Prozesses ist. Ich habe auch gesehen, dass SIGHUPes aus nicht terminierenden Gründen verwendet wurde, z. B. um einem Dämon mitzuteilen, dass er Ihre Konfigurationsdatei erneut lesen soll. Und es scheint mir, dass SIGINT(der gleiche Interrupt, den Sie normalerweise mit Strg-C bekommen, oder?) Nicht so weit verbreitet ist, wie es sein sollte, oder eher unanständig endet.

Angesichts dessen, dass dies SIGKILLein letzter Ausweg ist - Welche Signale und in welcher Reihenfolge sollten Sie an einen beliebigen Prozess senden, um ihn so elegant wie möglich zu beenden?

Bitte begründen Sie Ihre Antworten mit unterstützenden Fakten (über persönliche Vorlieben oder Meinungen hinaus) oder Referenzen, wenn Sie können.

Hinweis: Ich interessiere mich besonders für Best Practices, die die Berücksichtigung von Bash / Cygwin beinhalten.

Bearbeiten: Bisher scheint niemand INT oder QUIT zu erwähnen, und HUP wird nur begrenzt erwähnt. Gibt es einen Grund, diese in ein geordnetes Prozess-Töten einzubeziehen?

System PAUSE
quelle
4
Wenn Sie auf SIGKILL zurückgreifen müssen, um einen Prozess wirklich zu beenden, würde ich dies als Fehler im Programm betrachten.
Sigjuice

Antworten:

114

SIGTERM weist eine Anwendung an, beendet zu werden. Die anderen Signale teilen der Anwendung andere Dinge mit, die nicht mit dem Herunterfahren zusammenhängen, aber manchmal das gleiche Ergebnis haben können. Verwenden Sie diese nicht. Wenn Sie möchten, dass eine Anwendung heruntergefahren wird, teilen Sie dies mit. Geben Sie keine irreführenden Signale.

Einige Leute glauben, dass die intelligente Standardmethode zum Beenden eines Prozesses darin besteht, eine Reihe von Signalen zu senden, wie z. B. HUP, INT, TERM und schließlich KILL. Das ist lächerlich. Das richtige Signal für die Beendigung ist SIGTERM. Wenn SIGTERM den Prozess nicht sofort beendet, wie Sie es vielleicht bevorzugen, liegt dies daran, dass die Anwendung das Signal verarbeitet hat. Das heißt, es hat einen sehr guten Grund, nicht sofort zu kündigen: Es müssen Aufräumarbeiten durchgeführt werden. Wenn Sie diese Bereinigungsarbeit mit anderen Signalen unterbrechen, ist nicht abzusehen, welche Daten aus dem Speicher noch nicht auf der Festplatte gespeichert sind, welche Clientanwendungen hängen bleiben oder ob Sie sie "mitten im Satz" unterbrechen, was effektiv zu einer Datenbeschädigung führt.

Weitere Informationen zur tatsächlichen Bedeutung der Signale finden Sie unter Sigaction (2). Verwechseln Sie "Standardaktion" nicht mit "Beschreibung", sie sind nicht dasselbe.

SIGINT wird verwendet, um einen interaktiven "Tastatur-Interrupt" des Prozesses zu signalisieren. Einige Programme behandeln die Situation möglicherweise auf besondere Weise für Terminalbenutzer.

SIGHUP wird verwendet, um zu signalisieren, dass das Terminal verschwunden ist und den Prozess nicht mehr betrachtet. Das ist alles. Einige Prozesse werden als Reaktion darauf heruntergefahren, im Allgemeinen, weil ihr Betrieb ohne Terminal keinen Sinn ergibt, andere entscheiden sich für andere Dinge, z. B. das erneute Überprüfen von Konfigurationsdateien.

SIGKILL wird verwendet, um den Prozess zwangsweise aus dem Kernel zu entfernen. Es ist insofern besonders, als es eigentlich kein Signal für den Prozess ist, sondern direkt vom Kernel interpretiert wird.

Senden Sie kein SIGKILL. SIGKILL sollte auf keinen Fall per Skript gesendet werden. Wenn die Anwendung das SIGTERM verarbeitet, kann die Bereinigung eine Sekunde dauern, es kann eine Minute dauern, es kann eine Stunde dauern . Abhängig davon, was die Anwendung erledigen muss, bevor sie beendet werden kann. Jede Logik, die die Bereinigungssequenz einer Anwendung " annimmt ", hat lange genug gedauert und muss nach X Sekunden verkürzt oder SIGKILLiert werden. Das ist einfach falsch .

Der einzige Grund, warum eine Anwendung zum Beenden ein SIGKILL benötigen würde , besteht darin, dass während der Bereinigungssequenz ein Fehler aufgetreten ist. In diesem Fall können Sie ein Terminal öffnen und manuell SIGKILLIEREN. Abgesehen davon ist der einzige andere Grund, warum Sie etwas SIGKILLIEREN würden , dass Sie verhindern möchten , dass es sich selbst aufräumt.

Obwohl die halbe Welt nach 5 Sekunden blind SIGKILL sendet, ist es immer noch schrecklich falsch, dies zu tun.

lhunath
quelle
13
Sie haben Recht, dass es da draußen eine Menge Missbrauch von SIGKILL gibt. Aber es gibt eine Zeit und einen Ort, um es zu verwenden, selbst aus einem Skript. Viele, viele Apps fangen SIGTERM ein und beenden sie ordnungsgemäß in weniger als einer Sekunde oder innerhalb weniger Sekunden. Eine davon läuft noch 30 Sekunden später, weil sie eingeklemmt ist.
dwc
4
@dwc: Versuchen Sie, es einmal für eine Stunde laufen zu lassen. Wenn es nicht stirbt, ist es "eingeklemmt" und repariert es entweder oder ist faul und SIGKILLIERT es in Zukunft nach einiger Zeit. Beachten Sie, dass Sie wahrscheinlich Dinge beschädigen, und denken Sie daran, dass Sie dies NICHT "standardmäßig" tun sollten.
lhunath
2
@lhunath: Ich hoffe, es macht Ihnen nichts aus, ich habe Ihre Absätze neu angeordnet, damit die Antwort direkter und klarer aus der Frage folgt. Das Anti-SIGKILL-Geschwätz ist gutes Zeug, aber ein sekundärer Punkt. Nochmals vielen Dank für eine ausgezeichnete und lehrreiche Antwort.
System PAUSE
8
Senden Sie kein SIGKILL. Je. Einfach falsch. "Ja wirklich?" Auch wenn Ihr System dank Endlosschleifen bereits brennt. Viel Glück. -1
konsolebox
//, Upvoting für Das ist lächerlich.
Nathan Basanese
16

Kurze Antwort : Senden SIGTERM, 30 Sekunden später SIGKILL. Das heißt, senden SIGTERM, etwas warten (es kann von Programm zu Programm variieren, Sie kennen Ihr System vielleicht besser, aber 5 bis 30 Sekunden reichen aus. Wenn Sie eine Maschine herunterfahren, wird sie möglicherweise automatisch bis zu 1'30 Sekunden warten. Warum doch die Eile?), Dann senden SIGKILL.

Angemessene Antwort : SIGTERM, SIGINT, das SIGKILL ist mehr als genug. Der Prozess wird sehr wahrscheinlich vorher beendet SIGKILL.

Lange Antwort : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Dies ist nicht erforderlich, aber zumindest führen Sie den Prozess in Bezug auf Ihre Nachricht nicht in die Irre. Alle diese Signale haben meinen Sie den Prozess stoppen soll , was es tut und beenden.

Egal welche Antwort Sie aus dieser Erklärung wählen, denken Sie daran!

Wenn Sie ein Signal senden, das etwas anderes bedeutet, kann der Prozess (auf der einen Seite) auf sehr unterschiedliche Weise damit umgehen. Wenn der Prozess das Signal jedoch nicht verarbeitet, spielt es keine Rolle, was Sie senden, der Prozess wird trotzdem beendet (wenn die Standardaktion natürlich das Beenden ist).

Sie müssen also als Programmierer denken. Würden Sie einen Funktionshandler codieren, SIGHUPum beispielsweise ein Programm zu beenden, das eine Verbindung zu etwas herstellt, oder würden Sie eine Schleife ausführen, um erneut zu versuchen, eine Verbindung herzustellen? Das ist hier die Hauptfrage! Deshalb ist es wichtig, nur Signale zu senden, die genau das bedeuten, was Sie beabsichtigen.

Fast dumme lange Antwort :

Die folgende Tabelle enthält die relevanten Signale und die Standardaktionen, falls das Programm sie nicht verarbeitet.

Ich habe sie in der Reihenfolge bestellt, in der ich sie verwenden möchte (übrigens, ich empfehle Ihnen, die vernünftige Antwort zu verwenden , nicht diese hier), wenn Sie sie wirklich alle ausprobieren müssen (es würde Spaß machen zu sagen, dass die Tabelle in Bezug auf bestellt ist die Zerstörung, die sie verursachen können, aber das ist nicht ganz richtig).

Die mit einem Sternchen (*) gekennzeichneten Signale werden NICHT empfohlen. Das Wichtigste dabei ist, dass Sie möglicherweise nie wissen, wofür es programmiert ist. Speziell SIGUSR! Es kann die Apokalipse starten (es ist ein freies Signal für einen Programmierer, zu tun, was er / sie will!). Wenn dies jedoch nicht behandelt wird ODER in dem unwahrscheinlichen Fall, dass es zum Beenden behandelt wird, wird das Programm beendet.

In der Tabelle bleiben die Signale mit den Standardoptionen zum Beenden und Generieren eines Core-Dumps am Ende kurz davor 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

Dann würde ich für diese vorschlägt fast dumm lange Antwort : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

Und schließlich die

Auf jeden Fall dumm lange lange Antwort :

Versuchen Sie das nicht zu Hause.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEUnd wenn nichts funktioniert, SIGKILL.

SIGUSR2sollte vorher versucht werden, SIGUSR1da wir besser dran sind, wenn das Programm das Signal nicht verarbeitet. Und es ist viel wahrscheinlicher, dass es damit umgeht, SIGUSR1wenn es nur mit einem von ihnen umgeht.

Übrigens, der KILL : Es ist nicht falsch, SIGKILLan einen Prozess zu senden , wie andere Antworten sagten. Überlegen Sie, was passiert, wenn Sie einen shutdownBefehl senden ? Es wird versuchen SIGTERMund SIGKILLnur. Warum ist das Ihrer Meinung nach der Fall? Und warum brauchen Sie andere Signale, wenn der shutdownBefehl nur diese beiden verwendet?


Zurück zur langen Antwort : Dies ist ein netter Oneliner:

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

Zwischen den Signalen wird 30 Sekunden lang geschlafen. Warum sonst brauchen Sie einen Oneliner ? ;)

Empfohlen wird auch: Versuchen Sie es nur mit Signalen 15 2 9aus der vernünftigen Antwort .

Sicherheit : Entfernen Sie die zweite, echowenn Sie bereit sind. Ich nenne es mein dry-runfür Onliner . Verwenden Sie es immer zum Testen.


Skript killgracefully

Eigentlich war ich von dieser Frage so fasziniert, dass ich mich entschied, ein kleines Skript zu erstellen, um genau das zu tun. Bitte laden Sie es hier herunter (klonen):

GitHub-Link zum Killgracefully-Repository

Dr. Beco
quelle
7

Normalerweise senden Sie SIGTERMdie Standardeinstellung "Töten". Dies ist aus einem bestimmten Grund die Standardeinstellung. Nur wenn ein Programm nicht in angemessener Zeit heruntergefahren wird, sollten Sie darauf zurückgreifen SIGKILL. Beachten Sie jedoch, dass SIGKILLdas Programm keine Möglichkeit zum Bereinigen bietet und Daten beschädigt werden können.

Was SIGHUP, HUPsteht für „aufhängen“ und historisch gemeint , dass das Modem getrennt. Es ist im Wesentlichen gleichbedeutend mit SIGTERM. Der Grund, warum Dämonen manchmal SIGHUPzum Neustarten oder Neuladen von Konfigurationen verwendet werden, besteht darin, dass Dämonen von allen steuernden Terminals getrennt werden, da ein Dämon diese nicht benötigt und daher niemals empfangen würde SIGHUP, sodass dieses Signal für den allgemeinen Gebrauch als "freigegeben" angesehen wurde. Nicht alle Dämonen verwenden dies zum Nachladen! Die Standardaktion für SIGHUP ist das Beenden und viele Dämonen verhalten sich so! Sie können also nicht blindlings SIGHUPs an Dämonen senden und erwarten, dass sie überleben.

Bearbeiten: Es SIGINT ist wahrscheinlich unangemessen, einen Prozess zu beenden, da er normalerweise an ^Cdie Terminaleinstellung gebunden ist oder was auch immer die Terminaleinstellung ist, um ein Programm zu unterbrechen. Viele Programme erfassen dies für ihre eigenen Zwecke, daher ist es häufig genug, dass es nicht funktioniert. SIGQUITIn der Regel wird standardmäßig ein Core-Dump erstellt. Wenn Sie nicht möchten, dass Core-Dateien herumliegen, ist dies auch kein guter Kandidat.

Zusammenfassung: Wenn Sie senden SIGTERMund das Programm nicht innerhalb Ihres Zeitrahmens stirbt, senden Sie es SIGKILL.

dwc
quelle
4
Beachten Sie, dass die Nachverfolgung mit SIGKILL nur in Situationen erfolgen sollte, in denen das sofortige Herunterfahren eine höhere Priorität hat als die Verhinderung von Datenverlust / Datenbeschädigung.
Thomasrutter
@dwc Ich habe den folgenden Punkt in Ihrer Antwort nicht verstanden. Könnten Sie bitte helfen? "Der Grund, warum Daemons manchmal SIGHUP verwenden, um die Konfiguration neu zu starten oder neu zu laden, ist, dass sich Daemons von allen steuernden Terminals trennen und daher niemals SIGTERM empfangen würden, sodass das Signal für den allgemeinen Gebrauch als" freigegeben "angesehen wurde."
Jack
3
@Jack Lassen Sie mich versuchen: SIGHUP ist das "Auflegen" -Signal, das einem Prozess mitteilt, dass das Terminal getrennt wurde. Da Daemons im Hintergrund ausgeführt werden, benötigen sie keine Terminals. Das bedeutet, dass ein "Auflegen" -Signal für Dämonen nicht relevant ist. Sie erhalten es niemals von einer Terminal-Trennung, da sie überhaupt keine Terminals angeschlossen haben. Und da das Signal sowieso definiert ist, obwohl sie es nicht für den ursprünglichen Zweck benötigen, verwenden viele Dämonen es stattdessen für einen anderen Zweck, beispielsweise zum erneuten Lesen ihrer Konfigurationsdateien.
System PAUSE
Danke System PAUSE. das ist hilfreich.
Jack
6

SIGTERMbedeutet eigentlich, einer Bewerbung eine Nachricht zu senden: " Würdest du so nett sein und Selbstmord begehen " ? Es kann von der Anwendung abgefangen und verarbeitet werden, um Bereinigungs- und Herunterfahrcode auszuführen.

SIGKILLkann nicht durch Anwendung gefangen werden. Die Anwendung wird vom Betriebssystem beendet, ohne dass eine Bereinigung möglich ist.

Es ist typisch, SIGTERMzuerst zu senden , einige Zeit zu schlafen und dann zu senden SIGKILL.

vartec
quelle
Ich nehme an, die Umfrage wäre etwas effizienter als das Schlafen (vor dem SIGKILL)
Ohad Schneider,
@OhadSchneider würde es, aber das würde etwas mehr als einen einfachen Bash-Befehl erfordern.
Vartec
Ja, ich denke, Sie müssten eine Schleife ausführen, während der Prozess noch läuft . Verwenden Sie dazu Folgendes : stackoverflow.com/a/15774758/67824 .
Ohad Schneider
5
  • SIGTERM entspricht dem "Klicken auf das 'X'" in einem Fenster.
  • SIGTERM wird von Linux zuerst verwendet, wenn es heruntergefahren wird.
gbarry
quelle
Das wollte ich wissen. +1. Vielen Dank.
Luc
6
"SIGTERM ist gleichbedeutend mit" Klicken auf das 'X' "in einem Fenster" Nein, das ist es nicht, da jede Anwendung problemlos eine beliebige Anzahl von (Dokument- und Werkzeug-) Fenstern öffnen kann, geschweige denn Dialoge, und dies möglicherweise nicht Reagieren Sie sogar auf einen Befehl zum Schließen eines letzten Fensters wie auf einen Befehl zum Beenden (ich kann mir keine offensichtlichen Beispiele vorstellen, aber obwohl dies nicht offensichtlich ist, gibt es keinen Grund, warum dies nicht so gemacht werden kann). SIGTERM ist (oder sollte) gleichbedeutend damit, die Anwendung ordnungsgemäß zum Beenden aufzufordern, dies kann jedoch in dieser bestimmten Anwendung ausgeführt werden .
Benutzer
2

Bei all den Diskussionen hier wurde kein Code angeboten. Hier ist meine Einstellung:

#!/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
Ohad Schneider
quelle
0

HUP klingt für mich nach Müll. Ich würde es senden, damit ein Daemon seine Konfiguration erneut liest.

SIGTERM kann abgefangen werden; Ihre Daemons müssen möglicherweise Bereinigungscode ausführen, wenn sie dieses Signal empfangen. Das können Sie für SIGKILL nicht tun. Mit SIGKILL geben Sie dem Autor des Dämons also keine Optionen.

Mehr dazu auf Wikipedia

innaM
quelle