signal — Handler für asynchrone Ereignisse setzen

Quellcode: Lib/signal.py


Dieses Modul bietet Mechanismen zur Verwendung von Signalhandlern in Python.

Allgemeine Regeln

Die Funktion signal.signal() erlaubt die Definition benutzerdefinierter Handler, die ausgeführt werden, wenn ein Signal empfangen wird. Eine kleine Anzahl von Standardhandlern ist installiert: SIGPIPE wird ignoriert (sodass Schreibfehler bei Pipes und Sockets als gewöhnliche Python-Ausnahmen gemeldet werden können) und SIGINT wird in eine KeyboardInterrupt-Ausnahme umgewandelt, wenn der Elternprozess diese nicht geändert hat.

Ein Handler für ein bestimmtes Signal bleibt nach der Installation so lange aktiv, bis er explizit zurückgesetzt wird (Python emuliert die BSD-Schnittstelle unabhängig von der zugrundeliegenden Implementierung), mit Ausnahme des Handlers für SIGCHLD, der der zugrundeliegenden Implementierung folgt.

Auf WebAssembly-Plattformen werden Signale emuliert und verhalten sich daher anders. Mehrere Funktionen und Signale sind auf diesen Plattformen nicht verfügbar.

Ausführung von Python-Signalhandlern

Ein Python-Signalhandler wird nicht innerhalb des Low-Level- (C) Signalhandlers ausgeführt. Stattdessen setzt der Low-Level-Signalhandler ein Flag, das die virtuelle Maschine anweist, den entsprechenden Python-Signalhandler zu einem späteren Zeitpunkt auszuführen (z. B. bei der nächsten Bytecode-Anweisung). Dies hat Konsequenzen

  • Es ist wenig sinnvoll, synchrone Fehler wie SIGFPE oder SIGSEGV abzufangen, die durch eine ungültige Operation im C-Code verursacht werden. Python kehrt vom Signalhandler zum C-Code zurück, der wahrscheinlich dasselbe Signal erneut auslöst und Python scheinbar hängen lässt. Ab Python 3.3 können Sie das Modul faulthandler verwenden, um synchrone Fehler zu melden.

  • Eine langlaufende, rein in C implementierte Berechnung (wie die Mustererkennung in einem großen Textkörper) kann ununterbrochen für eine beliebige Zeit ausgeführt werden, unabhängig von empfangenen Signalen. Die Python-Signalhandler werden aufgerufen, wenn die Berechnung abgeschlossen ist.

  • Wenn der Handler eine Ausnahme auslöst, wird diese "aus heiterem Himmel" im Hauptthread ausgelöst. Siehe die Anmerkung unten für eine Diskussion.

Signale und Threads

Python-Signalhandler werden immer im Haupt-Python-Thread des Hauptinterpreters ausgeführt, auch wenn das Signal in einem anderen Thread empfangen wurde. Das bedeutet, dass Signale nicht als Mittel zur Inter-Thread-Kommunikation verwendet werden können. Stattdessen können Sie die Synchronisationsprimitive aus dem Modul threading verwenden.

Außerdem darf nur der Hauptthread des Hauptinterpreters einen neuen Signalhandler setzen.

Modulinhalt

Geändert in Version 3.5: Signal (SIG*), Handler (SIG_DFL, SIG_IGN) und Sigmask (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK) zugehörige Konstanten, die unten aufgeführt sind, wurden in Enums (Signals, Handlers bzw. Sigmasks) umgewandelt. Die Funktionen getsignal(), pthread_sigmask(), sigpending() und sigwait() geben menschenlesbare Enums als Signals-Objekte zurück.

Das Signalmodul definiert drei Enums

class signal.Signals

enum.IntEnum-Sammlung von SIG*-Konstanten und den CTRL_* -Konstanten.

Hinzugefügt in Version 3.5.

class signal.Handlers

enum.IntEnum-Sammlung der Konstanten SIG_DFL und SIG_IGN.

Hinzugefügt in Version 3.5.

class signal.Sigmasks

enum.IntEnum-Sammlung der Konstanten SIG_BLOCK, SIG_UNBLOCK und SIG_SETMASK.

Verfügbarkeit: Unix.

Siehe die Manpage sigprocmask(2) und pthread_sigmask(3) für weitere Informationen.

Hinzugefügt in Version 3.5.

Die im Modul signal definierten Variablen sind

signal.SIG_DFL

Dies ist eine von zwei Standardoptionen für die Signalbehandlung; sie führt einfach die Standardfunktion für das Signal aus. Zum Beispiel ist die Standardaktion für SIGQUIT auf den meisten Systemen das Dumpen des Speichers und das Beenden, während die Standardaktion für SIGCHLD das einfache Ignorieren ist.

signal.SIG_IGN

Dies ist ein weiterer Standard-Signalhandler, der das gegebene Signal einfach ignoriert.

signal.SIGABRT

Abbruchsignal von abort(3).

signal.SIGALRM

Timer-Signal von alarm(2).

signal.SIGBREAK

Unterbrechung durch die Tastatur (STRG + BREAK).

Verfügbarkeit: Windows.

signal.SIGBUS

Busfehler (schlechter Speicherzugriff).

signal.SIGCHLD

Kindprozess gestoppt oder beendet.

signal.SIGCLD

Alias für SIGCHLD.

Verfügbarkeit: nicht macOS.

signal.SIGCONT

Fortsetzen des Prozesses, wenn er derzeit angehalten ist

signal.SIGFPE

Gleitkomma-Ausnahme. Zum Beispiel Division durch Null.

Siehe auch

ZeroDivisionError wird ausgelöst, wenn das zweite Argument einer Divisions- oder Modulo-Operation Null ist.

signal.SIGHUP

Auflegen auf dem steuernden Terminal oder Tod des steuernden Prozesses.

signal.SIGILL

Ungültige Instruktion.

signal.SIGINT

Unterbrechung durch die Tastatur (STRG + C).

Standardaktion ist das Auslösen von KeyboardInterrupt.

signal.SIGKILL

Kill-Signal.

Es kann nicht abgefangen, blockiert oder ignoriert werden.

signal.SIGPIPE

Gebrochene Pipe: Schreiben in eine Pipe ohne Leser.

Standardaktion ist das Ignorieren des Signals.

signal.SIGPROF

Profiling-Timer abgelaufen.

signal.SIGQUIT

Terminal-Quit-Signal.

signal.SIGSEGV

Speicherzugriffsverletzung: ungültige Speicherreferenz.

signal.SIGSTOP

Ausführung stoppen (kann nicht abgefangen oder ignoriert werden).

signal.SIGSTKFLT

Stackfehler am Coprozessor. Der Linux-Kernel löst dieses Signal nicht aus: es kann nur im Userspace ausgelöst werden.

Verfügbarkeit: Linux.

Auf Architekturen, auf denen das Signal verfügbar ist. Siehe die Manpage signal(7) für weitere Informationen.

Hinzugefügt in Version 3.11.

signal.SIGTERM

Terminierungssignal.

signal.SIGUSR1

Benutzersignale 1.

signal.SIGUSR2

Benutzersignale 2.

signal.SIGVTALRM

Virtueller Timer abgelaufen.

signal.SIGWINCH

Signal zur Fenstergrößenänderung.

SIG*

Alle Signalnummern sind symbolisch definiert. Zum Beispiel ist das Hangup-Signal als signal.SIGHUP definiert; die Variablennamen sind identisch mit den Namen, die in C-Programmen verwendet werden und in <signal.h> zu finden sind. Die Unix-Manpage für 'signal' listet die vorhandenen Signale auf (auf manchen Systemen ist dies signal(2), auf anderen sind die Listen in signal(7)). Beachten Sie, dass nicht alle Systeme den gleichen Satz von Signalnamen definieren; nur die vom System definierten Namen werden von diesem Modul definiert.

signal.CTRL_C_EVENT

Das Signal, das dem Tastaturereignis Strg+C entspricht. Dieses Signal kann nur mit os.kill() verwendet werden.

Verfügbarkeit: Windows.

Hinzugefügt in Version 3.2.

signal.CTRL_BREAK_EVENT

Das Signal, das dem Tastaturereignis Strg+Break entspricht. Dieses Signal kann nur mit os.kill() verwendet werden.

Verfügbarkeit: Windows.

Hinzugefügt in Version 3.2.

signal.NSIG

Eins mehr als die Anzahl der höchsten Signalnummer. Verwenden Sie valid_signals(), um gültige Signalnummern zu erhalten.

signal.ITIMER_REAL

Dekrementiert den Intervall-Timer in Echtzeit und sendet SIGALRM nach Ablauf.

signal.ITIMER_VIRTUAL

Dekrementiert den Intervall-Timer nur, wenn der Prozess ausgeführt wird, und sendet SIGVTALRM nach Ablauf.

signal.ITIMER_PROF

Dekrementiert den Intervall-Timer sowohl, wenn der Prozess ausgeführt wird, als auch wenn das System im Auftrag des Prozesses ausgeführt wird. Gekoppelt mit ITIMER_VIRTUAL wird dieser Timer normalerweise verwendet, um die vom Anwendungsprogramm im Benutzer- und Kernelmodus verbrachte Zeit zu profilieren. SIGPROF wird nach Ablauf gesendet.

signal.SIG_BLOCK

Ein möglicher Wert für den Parameter how in pthread_sigmask(), der angibt, dass Signale blockiert werden sollen.

Hinzugefügt in Version 3.3.

signal.SIG_UNBLOCK

Ein möglicher Wert für den Parameter how in pthread_sigmask(), der angibt, dass Signale entblockiert werden sollen.

Hinzugefügt in Version 3.3.

signal.SIG_SETMASK

Ein möglicher Wert für den Parameter how in pthread_sigmask(), der angibt, dass die Signalmaske ersetzt werden soll.

Hinzugefügt in Version 3.3.

Das Modul signal definiert eine Ausnahme

exception signal.ItimerError

Wird ausgelöst, um einen Fehler von der zugrundeliegenden Implementierung von setitimer() oder getitimer() zu signalisieren. Erwarten Sie diesen Fehler, wenn ein ungültiger Intervall-Timer oder eine negative Zeit an setitimer() übergeben wird. Dieser Fehler ist ein Untertyp von OSError.

Hinzugefügt in Version 3.3: Diese Ausnahme war früher ein Untertyp von IOError, das jetzt ein Alias von OSError ist.

Das Modul signal definiert die folgenden Funktionen

signal.alarm(time)

Wenn time ungleich Null ist, fordert diese Funktion an, dass ein SIGALRM-Signal an den Prozess in time Sekunden gesendet wird. Jeder zuvor geplante Alarm wird abgebrochen (nur ein Alarm kann zu einem bestimmten Zeitpunkt geplant werden). Der zurückgegebene Wert ist die Anzahl der Sekunden, bevor ein zuvor gesetzter Alarm ausgeliefert werden sollte. Wenn time Null ist, wird kein Alarm geplant und jeder geplante Alarm wird abgebrochen. Wenn der Rückgabewert Null ist, ist derzeit kein Alarm geplant.

Verfügbarkeit: Unix.

Siehe die Manpage alarm(2) für weitere Informationen.

signal.getsignal(signalnum)

Gibt den aktuellen Signalhandler für das Signal signalnum zurück. Der zurückgegebene Wert kann ein aufrufbares Python-Objekt sein oder einer der speziellen Werte signal.SIG_IGN, signal.SIG_DFL oder None sein. Hier bedeutet signal.SIG_IGN, dass das Signal zuvor ignoriert wurde, signal.SIG_DFL bedeutet, dass die Standardbehandlung für das Signal zuvor in Gebrauch war, und None bedeutet, dass der vorherige Signalhandler nicht aus Python installiert wurde.

signal.strsignal(signalnum)

Gibt die Beschreibung des Signals signalnum zurück, z. B. „Interrupt“ für SIGINT. Gibt None zurück, wenn signalnum keine Beschreibung hat. Löst ValueError aus, wenn signalnum ungültig ist.

Hinzugefügt in Version 3.8.

signal.valid_signals()

Gibt die Menge der gültigen Signalnummern auf dieser Plattform zurück. Dies kann kleiner sein als range(1, NSIG), wenn einige Signale vom System für interne Zwecke reserviert sind.

Hinzugefügt in Version 3.8.

signal.pause()

Veranlasst den Prozess, zu schlafen, bis ein Signal empfangen wird; der entsprechende Handler wird dann aufgerufen. Gibt nichts zurück.

Verfügbarkeit: Unix.

Siehe die Manpage signal(2) für weitere Informationen.

Siehe auch sigwait(), sigwaitinfo(), sigtimedwait() und sigpending().

signal.raise_signal(signum)

Sendet ein Signal an den aufrufenden Prozess. Gibt nichts zurück.

Hinzugefügt in Version 3.8.

signal.pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)

Sendet das Signal sig an den durch den Dateideskriptor pidfd bezeichneten Prozess. Python unterstützt den Parameter siginfo derzeit nicht; er muss None sein. Das Argument flags ist für zukünftige Erweiterungen vorgesehen; derzeit sind keine Flag-Werte definiert.

Siehe die Manpage pidfd_send_signal(2) für weitere Informationen.

Verfügbarkeit: Linux >= 5.1, Android >= Build-Zeit API Level 31

Hinzugefügt in Version 3.9.

signal.pthread_kill(thread_id, signalnum)

Sendet das Signal signalnum an den Thread thread_id, einen anderen Thread im selben Prozess wie der Aufrufer. Der Ziel-Thread kann beliebigen Code ausführen (Python oder nicht). Wenn der Ziel-Thread jedoch den Python-Interpreter ausführt, werden die Python-Signalhandler vom Haupt-Thread des Hauptinterpreters ausgeführt. Daher besteht der einzige Sinn des Sendens eines Signals an einen bestimmten Python-Thread darin, einen laufenden Systemaufruf mit InterruptedError fehlschlagen zu lassen.

Verwenden Sie threading.get_ident() oder das Attribut ident von threading.Thread-Objekten, um einen geeigneten Wert für thread_id zu erhalten.

Wenn signalnum 0 ist, wird kein Signal gesendet, aber die Fehlerprüfung wird trotzdem durchgeführt; dies kann verwendet werden, um zu prüfen, ob der Ziel-Thread noch läuft.

Löst ein Audit-Ereignis signal.pthread_kill mit den Argumenten thread_id, signalnum aus.

Verfügbarkeit: Unix.

Weitere Informationen finden Sie auf der Manpage pthread_kill(3).

Siehe auch os.kill().

Hinzugefügt in Version 3.3.

signal.pthread_sigmask(how, mask)

Ruft die Signalmaske des aufrufenden Threads ab und/oder ändert sie. Die Signalmaske ist die Menge der Signale, deren Zustellung für den Aufrufer derzeit blockiert ist. Gibt die alte Signalmaske als Menge von Signalen zurück.

Das Verhalten des Aufrufs hängt vom Wert von how ab, wie folgt.

  • SIG_BLOCK: Die Menge der blockierten Signale ist die Vereinigung der aktuellen Menge und des Arguments mask.

  • SIG_UNBLOCK: Die Signale in mask werden aus dem aktuellen Satz blockierter Signale entfernt. Es ist zulässig, zu versuchen, ein Signal zu entblockieren, das nicht blockiert ist.

  • SIG_SETMASK: Die Menge der blockierten Signale wird auf das Argument mask gesetzt.

mask ist eine Menge von Signalnummern (z. B. {signal.SIGINT, signal.SIGTERM}). Verwenden Sie valid_signals() für eine vollständige Maske, die alle Signale enthält.

Zum Beispiel liest signal.pthread_sigmask(signal.SIG_BLOCK, []) die Signalmaske des aufrufenden Threads.

SIGKILL und SIGSTOP können nicht blockiert werden.

Verfügbarkeit: Unix.

Siehe die Manpage sigprocmask(2) und pthread_sigmask(3) für weitere Informationen.

Siehe auch pause(), sigpending() und sigwait().

Hinzugefügt in Version 3.3.

signal.setitimer(which, seconds, interval=0.0)

Setzt den angegebenen Intervall-Timer (einen von signal.ITIMER_REAL, signal.ITIMER_VIRTUAL oder signal.ITIMER_PROF), der durch which angegeben ist, so, dass er nach seconds (float wird akzeptiert, anders als bei alarm()) und danach alle interval Sekunden (wenn interval ungleich Null ist) auslöst. Der durch which angegebene Intervall-Timer kann durch Setzen von seconds auf Null gelöscht werden.

Wenn ein Intervall-Timer auslöst, wird ein Signal an den Prozess gesendet. Das gesendete Signal hängt vom verwendeten Timer ab; signal.ITIMER_REAL liefert SIGALRM, signal.ITIMER_VIRTUAL sendet SIGVTALRM und signal.ITIMER_PROF liefert SIGPROF.

Die alten Werte werden als Tupel zurückgegeben: (delay, interval).

Der Versuch, einen ungültigen Intervall-Timer zu übergeben, führt zu einem ItimerError.

signal.getitimer(which)

Gibt den aktuellen Wert eines durch which angegebenen Intervall-Timers zurück.

signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)

Setzt den Wakeup-Dateideskriptor auf fd. Wenn ein Signal empfangen wird, für das Ihr Programm einen Signalhandler registriert hat, wird die Signalnummer als einzelnes Byte in die fd geschrieben. Wenn Sie keinen Signalhandler für die gewünschten Signale registriert haben, wird nichts in die Wakeup-fd geschrieben. Dies kann von einer Bibliothek verwendet werden, um einen poll- oder select-Aufruf aufzuwecken, sodass das Signal vollständig verarbeitet werden kann.

Die alte Wakeup-fd wird zurückgegeben (oder -1, wenn die Wakeup-Funktion über Dateideskriptoren nicht aktiviert war). Wenn fd -1 ist, ist die Wakeup-Funktion über Dateideskriptoren deaktiviert. Wenn nicht -1, muss fd nicht blockierend sein. Es liegt an der Bibliothek, alle Bytes aus fd zu entfernen, bevor poll oder select erneut aufgerufen wird.

Wenn Threads aktiviert sind, kann diese Funktion nur vom Haupt-Thread des Hauptinterpreters aufgerufen werden; der Versuch, sie von anderen Threads aus aufzurufen, führt zum Auslösen einer ValueError-Ausnahme.

Es gibt zwei gängige Möglichkeiten, diese Funktion zu verwenden. Bei beiden Ansätzen wird die fd zum Aufwecken bei einem Signal verwendet, aber dann unterscheiden sie sich darin, wie das Signal oder die Signale bestimmt werden, die eingegangen sind.

Beim ersten Ansatz lesen wir die Daten aus dem Puffer der fd, und die Byte-Werte geben Ihnen die Signalnummern. Dies ist einfach, aber in seltenen Fällen kann es zu einem Problem kommen: Im Allgemeinen hat die fd nur begrenzten Pufferplatz, und wenn zu viele Signale zu schnell eintreffen, kann der Puffer voll werden und einige Signale können verloren gehen. Wenn Sie diesen Ansatz verwenden, sollten Sie warn_on_full_buffer=True setzen, was zumindest eine Warnung auf stderr ausgibt, wenn Signale verloren gehen.

Beim zweiten Ansatz verwenden wir die Wakeup-fd nur zum Aufwecken und ignorieren die tatsächlichen Byte-Werte. In diesem Fall ist uns nur wichtig, ob der Puffer der fd leer oder nicht leer ist; ein voller Puffer stellt kein Problem dar. Wenn Sie diesen Ansatz verwenden, sollten Sie warn_on_full_buffer=False setzen, damit Ihre Benutzer nicht durch irreführende Warnmeldungen verwirrt werden.

Geändert in Version 3.5: Unter Windows unterstützt die Funktion jetzt auch Socket-Handles.

Geändert in Version 3.7: Hinzugefügt wurde der Parameter warn_on_full_buffer.

signal.siginterrupt(signalnum, flag)

Ändert das Wiederaufnahmeverhalten von Systemaufrufen: Wenn flag False ist, werden Systemaufrufe bei Unterbrechung durch Signal signalnum wieder aufgenommen, andernfalls werden Systemaufrufe unterbrochen. Gibt nichts zurück.

Verfügbarkeit: Unix.

Weitere Informationen finden Sie auf der Manpage siginterrupt(3).

Beachten Sie, dass die Installation eines Signalhandlers mit signal() das Wiederaufnahmeverhalten auf unterbrechbar zurücksetzt, indem implizit siginterrupt() mit einem wahren flag-Wert für das gegebene Signal aufgerufen wird.

signal.signal(signalnum, handler)

Setzt den Handler für Signal signalnum auf die Funktion handler. handler kann ein aufrufbares Python-Objekt sein, das zwei Argumente (siehe unten) annimmt, oder einer der speziellen Werte signal.SIG_IGN oder signal.SIG_DFL. Der vorherige Signalhandler wird zurückgegeben (siehe Beschreibung von getsignal() oben). (Siehe die Unix-Manpage signal(2) für weitere Informationen.)

Wenn Threads aktiviert sind, kann diese Funktion nur vom Haupt-Thread des Hauptinterpreters aufgerufen werden; der Versuch, sie von anderen Threads aus aufzurufen, führt zum Auslösen einer ValueError-Ausnahme.

Der handler wird mit zwei Argumenten aufgerufen: der Signalnummer und dem aktuellen Stack-Frame (None oder ein Frame-Objekt; eine Beschreibung von Frame-Objekten finden Sie in der Beschreibung in der Typenhierarchie oder in den Attributbeschreibungen im Modul inspect).

Unter Windows kann signal() nur mit SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM oder SIGBREAK aufgerufen werden. In jedem anderen Fall wird eine ValueError-Ausnahme ausgelöst. Beachten Sie, dass nicht alle Systeme die gleichen Signalnamen definieren; eine AttributeError wird ausgelöst, wenn ein Signalname nicht als Konstante auf Modulebene als SIG* definiert ist.

signal.sigpending()

Untersucht die Menge der Signale, die für die Zustellung an den aufrufenden Thread ausstehen (d. h. die Signale, die während der Blockierung ausgelöst wurden). Gibt die Menge der ausstehenden Signale zurück.

Verfügbarkeit: Unix.

Weitere Informationen finden Sie auf der Manpage sigpending(2).

Siehe auch pause(), pthread_sigmask() und sigwait().

Hinzugefügt in Version 3.3.

signal.sigwait(sigset)

Setzt die Ausführung des aufrufenden Threads aus, bis eines der in der Signalmenge sigset angegebenen Signale zugestellt wird. Die Funktion akzeptiert das Signal (entfernt es aus der Liste der ausstehenden Signale) und gibt die Signalnummer zurück.

Verfügbarkeit: Unix.

Weitere Informationen finden Sie auf der Manpage sigwait(3).

Siehe auch pause(), pthread_sigmask(), sigpending(), sigwaitinfo() und sigtimedwait().

Hinzugefügt in Version 3.3.

signal.sigwaitinfo(sigset)

Setzt die Ausführung des aufrufenden Threads aus, bis eines der in der Signalmenge sigset angegebenen Signale zugestellt wird. Die Funktion akzeptiert das Signal und entfernt es aus der Liste der ausstehenden Signale. Wenn eines der Signale in sigset für den aufrufenden Thread bereits aussteht, wird die Funktion sofort mit Informationen über dieses Signal zurückgegeben. Der Signalhandler wird für das zugestellte Signal nicht aufgerufen. Die Funktion löst eine InterruptedError aus, wenn sie durch ein Signal unterbrochen wird, das nicht in sigset enthalten ist.

Der Rückgabewert ist ein Objekt, das die Daten der siginfo_t-Struktur darstellt, nämlich: si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band.

Verfügbarkeit: Unix.

Weitere Informationen finden Sie auf der Manpage sigwaitinfo(2).

Siehe auch pause(), sigwait() und sigtimedwait().

Hinzugefügt in Version 3.3.

Geändert in Version 3.5: Die Funktion wird jetzt mit dem neu berechneten timeout erneut versucht, wenn sie durch ein Signal unterbrochen wird, das nicht in sigset enthalten ist, und der Signalhandler keine Ausnahme auslöst (siehe PEP 475 für die Begründung).

signal.sigtimedwait(sigset, timeout)

Wie sigwaitinfo(), nimmt aber ein zusätzliches Argument timeout entgegen, das ein Timeout angibt. Wenn timeout als 0 angegeben wird, wird ein Poll durchgeführt. Gibt None zurück, wenn ein Timeout auftritt.

Verfügbarkeit: Unix.

Weitere Informationen finden Sie auf der Manpage sigtimedwait(2).

Siehe auch pause(), sigwait() und sigwaitinfo().

Hinzugefügt in Version 3.3.

Geändert in Version 3.5: Die Funktion wird jetzt mit dem neu berechneten timeout erneut versucht, wenn sie durch ein Signal unterbrochen wird, das nicht in sigset enthalten ist, und der Signalhandler keine Ausnahme auslöst (siehe PEP 475 für die Begründung).

Beispiele

Hier ist ein minimales Beispielprogramm. Es verwendet die Funktion alarm(), um die Zeit zu begrenzen, die mit dem Öffnen einer Datei verbracht wird; dies ist nützlich, wenn die Datei für ein serielles Gerät bestimmt ist, das möglicherweise nicht eingeschaltet ist, was normalerweise dazu führen würde, dass os.open() unendlich hängt. Die Lösung besteht darin, vor dem Öffnen der Datei einen 5-Sekunden-Alarm einzustellen; wenn die Operation zu lange dauert, wird das Alarmsignal gesendet und der Handler löst eine Ausnahme aus.

import signal, os

def handler(signum, frame):
    signame = signal.Signals(signum).name
    print(f'Signal handler called with signal {signame} ({signum})')
    raise OSError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm

Hinweis zu SIGPIPE

Das Pipe-Ausgabe Ihres Programms an Tools wie head(1) löst ein SIGPIPE-Signal an Ihren Prozess aus, wenn der Empfänger der Standardausgabe frühzeitig schließt. Dies führt zu einer Ausnahme wie BrokenPipeError: [Errno 32] Broken pipe. Um diesen Fall zu behandeln, umschließen Sie Ihren Einstiegspunkt, um diese Ausnahme abzufangen, wie folgt:

import os
import sys

def main():
    try:
        # simulate large output (your code replaces this loop)
        for x in range(10000):
            print("y")
        # flush output here to force SIGPIPE to be triggered
        # while inside this try block.
        sys.stdout.flush()
    except BrokenPipeError:
        # Python flushes standard streams on exit; redirect remaining output
        # to devnull to avoid another BrokenPipeError at shutdown
        devnull = os.open(os.devnull, os.O_WRONLY)
        os.dup2(devnull, sys.stdout.fileno())
        sys.exit(1)  # Python exits with error code 1 on EPIPE

if __name__ == '__main__':
    main()

Setzen Sie die Disposition von SIGPIPE nicht auf SIG_DFL, um BrokenPipeError zu vermeiden. Dies würde dazu führen, dass Ihr Programm unerwartet beendet wird, wenn eine Socket-Verbindung unterbrochen wird, während Ihr Programm noch darauf schreibt.

Hinweis zu Signalhandlern und Ausnahmen

Wenn ein Signalhandler eine Ausnahme auslöst, wird die Ausnahme zum Haupt-Thread weitergeleitet und kann nach jeder Bytecode-Instruktion ausgelöst werden. Insbesondere kann eine KeyboardInterrupt zu jedem Zeitpunkt während der Ausführung auftreten. Die meisten Python-Codes, einschließlich der Standardbibliothek, können dagegen nicht robust gemacht werden, und daher kann eine KeyboardInterrupt (oder jede andere Ausnahme, die aus einem Signalhandler resultiert) in seltenen Fällen das Programm in einen unerwarteten Zustand versetzen.

Um dieses Problem zu veranschaulichen, betrachten Sie den folgenden Code

class SpamContext:
    def __init__(self):
        self.lock = threading.Lock()

    def __enter__(self):
        # If KeyboardInterrupt occurs here, everything is fine
        self.lock.acquire()
        # If KeyboardInterrupt occurs here, __exit__ will not be called
        ...
        # KeyboardInterrupt could occur just before the function returns

    def __exit__(self, exc_type, exc_val, exc_tb):
        ...
        self.lock.release()

Für viele Programme, insbesondere solche, die bei KeyboardInterrupt einfach nur beendet werden sollen, ist dies kein Problem. Komplexe oder hochzuverlässige Anwendungen sollten jedoch das Auslösen von Ausnahmen aus Signalhandlern vermeiden. Sie sollten auch KeyboardInterrupt nicht als Mittel zum ordnungsgemäßen Herunterfahren abfangen. Stattdessen sollten sie ihren eigenen SIGINT-Handler installieren. Unten finden Sie ein Beispiel für einen HTTP-Server, der KeyboardInterrupt vermeidet

import signal
import socket
from selectors import DefaultSelector, EVENT_READ
from http.server import HTTPServer, SimpleHTTPRequestHandler

interrupt_read, interrupt_write = socket.socketpair()

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    interrupt_write.send(b'\0')
signal.signal(signal.SIGINT, handler)

def serve_forever(httpd):
    sel = DefaultSelector()
    sel.register(interrupt_read, EVENT_READ)
    sel.register(httpd, EVENT_READ)

    while True:
        for key, _ in sel.select():
            if key.fileobj == interrupt_read:
                interrupt_read.recv(1)
                return
            if key.fileobj == httpd:
                httpd.handle_request()

print("Serving on port 8000")
httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
serve_forever(httpd)
print("Shutdown...")