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
SIGFPEoderSIGSEGVabzufangen, 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 Modulfaulthandlerverwenden, 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 KonstantenSIG_DFLundSIG_IGN.Hinzugefügt in Version 3.5.
- class signal.Sigmasks¶
enum.IntEnum-Sammlung der KonstantenSIG_BLOCK,SIG_UNBLOCKundSIG_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
SIGQUITauf den meisten Systemen das Dumpen des Speichers und das Beenden, während die Standardaktion fürSIGCHLDdas einfache Ignorieren ist.
- signal.SIG_IGN¶
Dies ist ein weiterer Standard-Signalhandler, der das gegebene Signal einfach ignoriert.
- signal.SIGALRM¶
Timer-Signal von alarm(2).
Verfügbarkeit: Unix.
- signal.SIGBREAK¶
Unterbrechung durch die Tastatur (STRG + BREAK).
Verfügbarkeit: Windows.
- signal.SIGBUS¶
Busfehler (schlechter Speicherzugriff).
Verfügbarkeit: Unix.
- signal.SIGCHLD¶
Kindprozess gestoppt oder beendet.
Verfügbarkeit: Unix.
- signal.SIGCLD¶
Alias für
SIGCHLD.Verfügbarkeit: nicht macOS.
- signal.SIGCONT¶
Fortsetzen des Prozesses, wenn er derzeit angehalten ist
Verfügbarkeit: Unix.
- signal.SIGFPE¶
Gleitkomma-Ausnahme. Zum Beispiel Division durch Null.
Siehe auch
ZeroDivisionErrorwird 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.
Verfügbarkeit: Unix.
- 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.
Verfügbarkeit: Unix.
- signal.SIGPIPE¶
Gebrochene Pipe: Schreiben in eine Pipe ohne Leser.
Standardaktion ist das Ignorieren des Signals.
Verfügbarkeit: Unix.
- signal.SIGPROF¶
Profiling-Timer abgelaufen.
Verfügbarkeit: Unix.
- signal.SIGQUIT¶
Terminal-Quit-Signal.
Verfügbarkeit: Unix.
- 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.
Verfügbarkeit: Unix.
- signal.SIGUSR2¶
Benutzersignale 2.
Verfügbarkeit: Unix.
- signal.SIGVTALRM¶
Virtueller Timer abgelaufen.
Verfügbarkeit: Unix.
- signal.SIGWINCH¶
Signal zur Fenstergrößenänderung.
Verfügbarkeit: Unix.
- SIG*
Alle Signalnummern sind symbolisch definiert. Zum Beispiel ist das Hangup-Signal als
signal.SIGHUPdefiniert; 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_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()odergetitimer()zu signalisieren. Erwarten Sie diesen Fehler, wenn ein ungültiger Intervall-Timer oder eine negative Zeit ansetitimer()übergeben wird. Dieser Fehler ist ein Untertyp vonOSError.
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_DFLoderNonesein. Hier bedeutetsignal.SIG_IGN, dass das Signal zuvor ignoriert wurde,signal.SIG_DFLbedeutet, dass die Standardbehandlung für das Signal zuvor in Gebrauch war, undNonebedeutet, 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. GibtNonezurück, wenn signalnum keine Beschreibung hat. LöstValueErroraus, 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()undsigpending().
- 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
Nonesein. 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-ZeitAPI Level 31Hinzugefü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
InterruptedErrorfehlschlagen zu lassen.Verwenden Sie
threading.get_ident()oder das Attributidentvonthreading.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_killmit den Argumententhread_id,signalnumaus.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 Sievalid_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.SIGKILLundSIGSTOPkönnen nicht blockiert werden.Verfügbarkeit: Unix.
Siehe die Manpage sigprocmask(2) und pthread_sigmask(3) für weitere Informationen.
Siehe auch
pause(),sigpending()undsigwait().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_VIRTUALodersignal.ITIMER_PROF), der durch which angegeben ist, so, dass er nach seconds (float wird akzeptiert, anders als beialarm()) 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_REALliefertSIGALRM,signal.ITIMER_VIRTUALsendetSIGVTALRMundsignal.ITIMER_PROFliefertSIGPROF.Die alten Werte werden als Tupel zurückgegeben: (delay, interval).
Der Versuch, einen ungültigen Intervall-Timer zu übergeben, führt zu einem
ItimerError.Verfügbarkeit: Unix.
- signal.getitimer(which)¶
Gibt den aktuellen Wert eines durch which angegebenen Intervall-Timers zurück.
Verfügbarkeit: Unix.
- 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=Truesetzen, 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=Falsesetzen, 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
Falseist, 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 implizitsiginterrupt()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_IGNodersignal.SIG_DFL. Der vorherige Signalhandler wird zurückgegeben (siehe Beschreibung vongetsignal()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 mitSIGABRT,SIGFPE,SIGILL,SIGINT,SIGSEGV,SIGTERModerSIGBREAKaufgerufen werden. In jedem anderen Fall wird eineValueError-Ausnahme ausgelöst. Beachten Sie, dass nicht alle Systeme die gleichen Signalnamen definieren; eineAttributeErrorwird ausgelöst, wenn ein Signalname nicht als Konstante auf Modulebene alsSIG*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()undsigwait().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()undsigtimedwait().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
InterruptedErroraus, 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()undsigtimedwait().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 als0angegeben wird, wird ein Poll durchgeführt. GibtNonezurück, wenn ein Timeout auftritt.Verfügbarkeit: Unix.
Weitere Informationen finden Sie auf der Manpage sigtimedwait(2).
Siehe auch
pause(),sigwait()undsigwaitinfo().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...")