Laut der Python-Dokumentation kann der Aufruf signal.signal nur vom Hauptthread aufgerufen werden und Signalhandler werden im Hauptthread ausgeführt. Soweit ich weiß, bedeutet dies, dass ich im Hauptthread nichts wirklich tun kann, es sei denn, der Signalhandler macht etwas wirklich Einfaches, das durch Pythons GIL geschützt werden kann. Genauer gesagt kann kein im Hauptthread verwendetes Synchronisierungsobjekt vom Signal-Handler verwendet werden, da dies bedeuten würde, dass der Mutex beim Aufruf des Signal-Handlers möglicherweise bereits gesperrt ist und ein erneutes Sperren zu einem Deadlock führen würde, und selbst wenn der Mutex reentrant ist, würde dies zu Inkonsistenzen führen. Mein Ansatz ist also der folgende:
Code: Select all
signal.signal(signal.SIGCHLD, handle_sigchld)
t = threading.Thread(target=run_main_loop)
t.start()
try:
t.join()
except KeyboardInterrupt:
stop_main_loop()
t.join()
Es gibt andere Threads im Programm und Unterprozesse werden vom Thread der Hauptschleife gestartet. Ich erwarte, dass bei jedem Abschluss eines Unterprozesses der Signalhandler im Hauptthread aufgerufen wird, der eine Synchronisierungsmethode verwendet, um den Thread der Hauptschleife zu benachrichtigen. Es funktioniert auf dem Mac, aber unter Linux wird der Signalhandler nur aufgerufen, wenn der Thread beendet wird. Ich habe versucht, das
Problem mit strace zu debuggen, und das SIGCHLD kommt ordnungsgemäß an, wenn der Unterprozess abgeschlossen ist, aber es passiert in dem Thread, in dem der Prozess gestartet wurde, was möglicherweise der Grund dafür ist, dass der Signalhandler nicht im Hauptthread aufgerufen wird.
Um dieses
Problem zu umgehen, starte ich den Unterprozess wie folgt:
Code: Select all
def start_subprocess():
subprocess.Popen(...)
# from the main loop's thread
t = threading.Thread(target=start_subprocess)
t.start()
t.join()
Wenn wir nun strace prüfen, wird der Signalhandler im Hauptthread aufgerufen, vermutlich weil der Thread, der den Prozess gestartet hat, nicht mehr existiert.
Die Hauptfrage ist: Was passiert hier? Ist das ein Fehler in der Python-Implementierung oder ist nur die Dokumentation unklar? Gibt es eine elegantere Möglichkeit, das
Problem zu lösen?
Die Nebenfrage ist, ob meine ursprüngliche Annahme zutrifft, dass ich nicht dieselben Thread-Synchronisierungsmethoden vom Signalhandler und vom Hauptthread verwenden kann? Wenn nicht, warum nicht?