Wie behandeln Sie das signal in python auf windows-Maschine
Ich versuche den code eingefügt unter Windows, sondern der Umgang-signal, es ist die Tötung der Prozess.
Aber der gleiche code funktioniert in Ubuntu.
import os, sys
import time
import signal
def func(signum, frame):
print 'You raised a SigInt! Signal handler called with signal', signum
signal.signal(signal.SIGINT, func)
while True:
print "Running...",os.getpid()
time.sleep(2)
os.kill(os.getpid(),signal.SIGINT)
Du musst angemeldet sein, um einen Kommentar abzugeben.
Python ' s
os.kill
umschließt zwei fremden auf dem Windows-APIs. Es fordertGenerateConsoleCtrlEvent
, wenn diesig
parameter istCTRL_C_EVENT
oderCTRL_BREAK_EVENT
. In diesem Fall ist derpid
parameter eine Prozess-Gruppen-ID. Wenn dieser Aufruf fehlschlägt, und für alle anderensig
Werte, ruftOpenProcess
und dannTerminateProcess
. In diesem Fall ist derpid
parameter eine Prozess-ID, und diesig
Wert übergeben wird, wird als exit-code. Beenden einer Windows-Prozess ist vergleichbar mit dem sendenSIGKILL
zu einem POSIX-Prozess. In der Regel sollte dies vermieden werden, da es sich nicht erlauben, den Prozess zu beenden sauber.Beachten Sie, dass die Dokumente für
os.kill
fälschlicherweise behaupten, dass "kill() außerdem dauert der Prozess behandelt, getötet zu werden", das war nie wahr. Es fordertOpenProcess
um einen Prozess handle.Die Entscheidung über die WinAPI
CTRL_C_EVENT
undCTRL_BREAK_EVENT
stattSIGINT
undSIGBREAK
ist schade für cross-Plattform-code. Es ist auch nicht definiert, wasGenerateConsoleCtrlEvent
tut, wenn Sie übergeben eine Prozess-ID, das ist nicht ein Prozess-Gruppen-ID. Mit dieser Funktion in eine API, die eine Prozess-ID ist bedenklich am besten, und potenziell sehr falsch.Für Ihre Bedürfnisse zu finden Sie können schreiben, eine adapter-Funktion macht
os.kill
etwas freundlicher für cross-Plattform-code. Zum Beispiel:Diskussion
Windows nicht implementieren Signale an die system-Ebene [*]. Microsoft C runtime implementiert die sechs Signale, die erforderlich sind, durch standard-C:
SIGINT
,SIGABRT
,SIGTERM
,SIGSEGV
,SIGILL
, undSIGFPE
.SIGABRT
undSIGTERM
implementiert sind nur für den aktuellen Prozess. Sie können rufen Sie die handler über Craise
. Zum Beispiel (in Python 3.5):SIGTERM
ist nutzlos.Können Sie auch nicht viel mit
SIGABRT
mit dem signal-Modul, weil dieAbbrechen
Funktion tötet den Prozess, sobald der handler zurückkehrt, passiert das sofort, wenn mit dem signal-Modul die interne handler (es Reisen ein flag für die eingetragene Python aufrufbar aufgerufen werden, in dem Haupt-thread). Für Python 3 können Sie stattdessen die faulthandler Modul. Oder rufen Sie die CRT ' ssignal
Funktion über ctypes um eine ctypes callback als handler.CRT implementiert
SIGSEGV
,SIGILL
, undSIGFPE
durch setzen eines Windows structured exception handler für die entsprechende Windows-Ausnahmen:Dem CRT Umsetzung dieser Signale ist nicht kompatibel mit Python-signal handling. Der Ausnahme-filter ruft die registrierten handler und kehrt dann
EXCEPTION_CONTINUE_EXECUTION
. Jedoch, Python-handler nur Reisen, eine Flagge für den Interpreten zu nennen, die eingetragene callable irgendwann später in der Haupt-thread. Also den fehlerhaften code, der die Ausnahme ausgelöst wird weiter auslösen in einer endlos-Schleife. In Python 3 können Sie den faulthandler-Modul für diese Ausnahme-basierte Signale.Dass Blätter
SIGINT
, um die Windows-fügt die nicht-standard -SIGBREAK
. Beide Konsole und nicht Konsole Prozesse könnenraise
diese Signale, aber nur eine Konsole verarbeiten kann, erhalten Sie von einem anderen Prozess. Die CRT implementiert dies durch die Registrierung, die Kontrolle über eine Konsole event-handler überSetConsoleCtrlHandler
.Die Konsole sendet ein control-Ereignis durch erstellen eines neuen Threads in einem beigefügten Prozess, der mit der Ausführung beginnt bei
CtrlRoutine
im kernel32.dll oder kernelbase.dll (ohne Papiere). Dass der handler nicht ausgeführt wird auf dem Haupt-thread kann dazu führen, Probleme bei der Synchronisierung (z.B. in der REPL oder mitinput
). Auch ein control-Ereignis wird nicht unterbrechen Sie den Haupt-thread, wenn es blockiert beim warten auf ein synchronisationsobjekt warten oder synchroner I/O abgeschlossen ist. Pflege muss getroffen werden, um zu vermeiden, Blockierung der Haupt-thread, wenn es sein sollte, unterbrochen durchSIGINT
. Python 3 versuche um dies zu umgehen, indem Sie einen Windows-Ereignis-Objekt, das kann auch verwendet werden, in wartet, der sollte unterbrechbar durchSIGINT
.Wenn die Konsole sendet der Prozess eine
CTRL_C_EVENT
oderCTRL_BREAK_EVENT
, die CRT-handler ruft die registriertenSIGINT
oderSIGBREAK
handler, beziehungsweise. DieSIGBREAK
- handler wird auch als für dieCTRL_CLOSE_EVENT
dass die Konsole sendet, wenn das Fenster geschlossen ist. Python standardmäßig UmgangSIGINT
durch rasing eineKeyboardInterrupt
im Haupt-thread. AllerdingsSIGBREAK
ist zunächst die Standard -CTRL_BREAK_EVENT
handler, welche AnrufeExitProcess(STATUS_CONTROL_C_EXIT)
.Können Sie senden ein control-Ereignis für alle Prozesse an die aktuelle Konsole über
GenerateConsoleCtrlEvent
. Dies kann Ziel einer Teilmenge der Prozesse, die gehören zu einer Gruppe Prozess oder das Ziel der Gruppe 0 um das Ereignis zu senden, um alle Prozesse an die aktuelle Konsole.Prozess-Gruppen sind nicht gut dokumentiert Aspekt des Windows-API. Es gibt keine öffentliche API zur Abfrage der Gruppe von einem Prozess, aber jeder Prozess in einer Windows-Sitzung gehört zu einer Prozessgruppe, auch wenn es nur die wininit.exe group (services-Sitzung) oder winlogon.exe Gruppe (interaktive Sitzung). Eine neue Gruppe wird erstellt, indem die Schaffung Flagge
CREATE_NEW_PROCESS_GROUP
beim erstellen eines neuen Prozesses. Die Gruppen-ID ist die Prozess-ID des erzeugten Prozesses. Meines Wissens, ist die Konsole das einzige system, das verwendet die Prozess-Gruppe, und das ist nur fürGenerateConsoleCtrlEvent
.Was die Konsole macht, wenn die Ziel-ID ist nicht ein Prozess-Gruppen-ID ist nicht definiert und sollte nicht herangezogen werden. Wenn sowohl der Prozess und seine übergeordneten Prozess sind an der Konsole, schickt es dann ein control-Ereignis im Grunde wirkt wie das Ziel der Gruppe 0. Wenn der übergeordnete Prozess nicht an die aktuelle Konsole, dann
GenerateConsoleCtrlEvent
schlägt fehl, und dieos.kill
AnrufeTerminateProcess
. Komischerweise, wenn Sie als Ziel "System" - Prozess (PID 4) - und seine Kind-Prozess smss.exe (session manager), wird der Anruf erfolgreich ausgeführt, aber es passiert nichts, ausser, dass das Ziel versehentlich Hinzugefügt, um die Liste der angeschlossenen Prozesse (z.B.GetConsoleProcessList
). Es ist wahrscheinlich, weil der übergeordnete Prozess ist die "Leerlauf" - Verfahren, das, seit es PID 0, wird implizit angenommen, da die broadcast-PGID. Die übergeordnete Prozess-Regel gilt auch für nicht-Konsole-Prozesse. Auf einer nicht-Konsole-Kind-Prozess tut nichts-außer versehentlich beschädigt die Konsole Prozess-Liste, indem die angefügten Prozess. Ich hoffe, es ist klar, dass Sie sollten nur senden ein control-Ereignis entweder der Gruppe 0 oder eine bekannt - Prozess-Gruppe, die Sie erstellt haben, überCREATE_NEW_PROCESS_GROUP
.Verlassen Sie sich nicht auf die in der Lage zu senden
CTRL_C_EVENT
nichts aber die Gruppe 0, da es zunächst deaktiviert, in eine neue Prozess-Gruppe. Es ist nicht unmöglich, schicken Sie diese Veranstaltung, um eine neue Gruppe, aber das Ziel-Prozess zuerst aktivieren mussCTRL_C_EVENT
durch den AufrufSetConsoleCtrlHandler(NULL, FALSE)
.CTRL_BREAK_EVENT
ist alles, was Sie sich verlassen können, denn es kann nicht deaktiviert werden. Das senden dieser Veranstaltung ist eine einfache Möglichkeit, würdevoll zu töten, ein Kind-Prozess gestartet wurde mitCREATE_NEW_PROCESS_GROUP
, vorausgesetzt, es hat eine WindowsCTRL_BREAK_EVENT
oder CSIGBREAK
handler. Wenn nicht, wird der default-handler wird den Prozess zu beenden, Einstellung der exit-codeSTATUS_CONTROL_C_EXIT
. Zum Beispiel:Beachten Sie, dass
CTRL_BREAK_EVENT
war nicht geschickt, um den aktuellen Prozess, weil das Beispiel Ziele der Gruppe Prozess der Kind-Prozess (einschließlich aller seiner Kind-Prozesse an der Konsole, und so weiter). Wenn das Beispiel verwendet hatten, der Gruppe 0, den aktuellen Prozess hätte auch getötet, da ich nicht definierenSIGBREAK
handler. Lassen Sie uns versuchen, aber mit einem hf-set:[*]
Windows hat asynchrone Prozeduraufrufe (APC) in die Warteschlange ein Ziel-Funktion, um einen thread. Siehe den Artikel Innen-NT ist eine Asynchrone Prozedur-Aufruf für eine in-depth-Analyse von Windows APCs, insbesondere zur Klärung der Rolle der kernel-mode APCs. Sie können in die Warteschlange ein user-mode APC, um einen thread über
QueueUserAPC
. Sie bekommen auch in der Warteschlange vonReadFileEx
undWriteFileEx
für die I/O completion-routine.Ein user-mode APC ausgeführt wird, wenn der thread gibt eine warnbare wartet (z.B.
WaitForSingleObjectEx
oderSleepEx
mitbAlertable
alsTRUE
). Kernel-mode APCs, auf der anderen Seite erhalten, Versand sofort (wenn der IRQL untenAPC_LEVEL
). Sie sind in der Regel verwendet, durch die I/O-manager, um vollständige asynchrone I/O-Request-Pakete im Kontext des thread, der die Anforderung ausgegeben hat (z.B. kopieren von Daten aus dem IRP, um eine Benutzer-Modus-Puffer). Sehen Wartet und APCs für eine Tabelle, die zeigt, wie die APCs beeinflussen warnbare und nicht-warnbare wartet. Beachten Sie, dass die kernel-mode APCs unterbrechen Sie nicht warten, sondern ausgeführt werden intern durch die wait-routine.Windows umsetzen konnte POSIX-ähnliche Signale mit Hilfe von APCs, aber in der Praxis nutzt andere Mittel für den gleichen enden. Zum Beispiel:
__try
,__außer
,__endlich
,__leave
,RaiseException
,AddVectoredExceptionHandler
.Kernel Dispatcher-Objekte (d.h. Synchronisierung Von Objekten), z.B.
SetEvent
,SetWaitableTimer
.Fenster Nachrichten, z.B.
SendMessage
(ein-Fenster-Verfahren),PostMessage
(zu einem thread eine Nachrichtenwarteschlange geschickt werden, um eine window-Prozedur),PostThreadMessage
(zu einem thread-message-queue),WM_CLOSE
,WM_TIMER
.Fenster Nachrichten gesendet werden können, und veröffentlicht für alle threads, die den Aufruf thread ' s desktop und sind bei gleicher oder niedriger Integritätsstufe. Senden Sie ein Fenster mit der Meldung heißt es in einer system-queue aufrufen, um die Fensterprozedur, wenn der thread ruft
PeekMessage
oderGetMessage
. Eine Nachricht Hinzugefügt, um die thread-message-queue, die ein Kontingent von 10.000 Nachrichten. Einen thread mit message queue sollte eine message-Schleife zum verarbeiten der Warteschlange überGetMessage
undDispatchMessage
. Threads in einem nur für die Konsole Prozess in der Regel nicht über eine message queue. Jedoch die Konsolen-host-Prozess, conhost.exe offensichtlich tut. Wenn die schließen-Schaltfläche geklickt wird, oder wenn der primäre Prozess der Konsole getötet wird über den task-manager oder taskkill.exe, einWM_CLOSE
Nachricht gesendet, um die Nachrichten-queue der Konsole-Fenster-thread ist. Die Konsole schaltet sendet eineCTRL_CLOSE_EVENT
alle angeschlossenen Prozesse. Wenn ein Prozess das Ereignis behandelt, es gab 5 Sekunden, um würdevoll beenden, bevor es gewaltsam beendet.if sys.platform == 'win32': abandon_all_hope_ye_who_enter_here()
.signal.CTRL_BREAK_EVENT
zu stoppen, ein Python-Prozess verhindert den Aufruf deratexit
Handler also ich würde nicht nennen dies ein ordnungsgemäßes Herunterfahren. Aber vielen Dank für diese tolle Zusammenfassung, es ist wirklich hilfreich.CREATE_NEW_PROCESS_GROUP
und dass das Kind einen handler fürsignal.SIGBREAK
. Dies funktioniert für ein absichtliches signal von der übergeordneten. Leider ist es nicht den Fall behandeln, wenn das Konsole-Fenster wird geschlossen, aufgrund der Weg-Python-C-signal-handler setzt einfach ein flag, das anzeigt, das signal und gibt sofort (signal-Handler nur aufgerufen, in dem Haupt-thread). In diesem Fall behandeln, sollte ich diese überarbeiten zu beantworten, um eine ctypes Beispiel setzt eine Konsole steuerungshandler.