web-dev-qa-db-de.com

Schließen aller Threads mit einem Tastaturinterrupt

Ich versuche hier, einen Tastatur-Interrupt zu verwenden, um alle laufenden Threads im Programm zu beenden. Dies ist eine abgespeckte Version meines Codes, in dem der Thread erstellt wird:

for i in taskDictionary:
    try:
        sleep(60)
        thread = Thread(target = mainModule.executeThread)
        thread.start()
    except KeyboardInterrupt:
        thread.__stop()

Das Programm selbst ist weitaus komplizierter und berücksichtigt eine Vielzahl verschiedener Variablen, die sich auf die Threads auswirken, und es besteht sogar die Möglichkeit, in einem sequentiellen Modus zu starten, in dem die Aufgaben nicht in einem Thread ausgeführt werden, sondern einzeln gestartet werden, so dass Probleme auftreten können Mit dieser kleinen Variante habe ich gerade gezaubert ... Ich habe dies auf eine Weise getan, die 50/50 Ergebnisse hervorbrachte. Die Interrupts würden funktionieren, aber die Threads würden niemals sauber beendet. Manchmal würden sie weiterarbeiten, aber die Ausführung zukünftiger Threads anhalten, manchmal würden sie mit einem massiven Fehler in Bezug auf die Unterbrechung beendet werden, manchmal würden die Unterbrechungen überhaupt nichts tun. Als ich das letzte Mal ausgeführt habe, hat das Programm die Ausführung aller zukünftigen Threads angehalten, aber den aktuellen Thread nicht gestoppt. Gibt es eine Möglichkeit, die Threads zu beenden, ohne in das Modul zu gehen, in dem der Thread tatsächlich ausgeführt wird?

34
Joe

Eine ähnliche Frage lautet: "Wie töten Sie einen Thread?"

Sie erstellen einen Exit-Handler in Ihrem Thread, der von einem Sperr- oder Ereignisobjekt aus dem Threading-Modul gesteuert wird. Sie entfernen dann einfach die Sperre oder signalisieren das Ereignisobjekt. Dies informiert den Thread, dass er die Verarbeitung beenden und ordnungsgemäß beenden sollte. Nachdem Sie den Thread im Hauptprogramm signalisiert haben, müssen Sie nur noch die thread.join()-Methode in main verwenden, die auf das Herunterfahren des Threads wartet.

Ein kurzes Beispiel:

import threading
import time

def timed_output(name, delay, run_event):
    while run_event.is_set():
        time.sleep(delay)
        print name,": New Message!"


def main():
    run_event = threading.Event()
    run_event.set()
    d1 = 1
    t1 = threading.Thread(target = timed_output, args = ("bob",d1,run_event))

    d2 = 2
    t2 = threading.Thread(target = timed_output, args = ("paul",d2,run_event))

    t1.start()
    time.sleep(.5)
    t2.start()

    try:
        while 1:
            time.sleep(.1)
    except KeyboardInterrupt:
        print "attempting to close threads. Max wait =",max(d1,d2)
        run_event.clear()
        t1.join()
        t2.join()
        print "threads successfully closed"

if __== '__main__':
    main()

Wenn Sie wirklich die Funktionalität von kill a thread benötigen, verwenden Sie Multiprocessing. Sie können SIGTERMs an einzelne "Prozesse" senden (es ist auch dem Threading-Modul sehr ähnlich). Im Allgemeinen gilt für Threading, wenn Sie IO-gebunden sind, und für Multiprocessing, wenn Sie wirklich prozessorbezogen sind.

54
Paul Seeb

Es gibt einige Optionen, bei denen keine Sperren oder andere Signale zwischen Threads verwendet werden müssen. Man setzt die Threads als daemons , die automatisch beendet werden, wenn der Haupt-Thread beendet wird. Die andere ist die Verwendung von Prozess , die stattdessen eine Beendigungsmethode haben, die Sie vom Hauptprozess aus aufrufen können, wenn Sie sie beenden und das Hauptprogramm laufen lassen müssen.

Beides ist besonders nützlich, wenn Sie für die Eingabe Threads blockieren. Die Verwendung eines Timeouts und das periodische Prüfen des Signals würden in den meisten Fällen ohne zu viel Overhead funktionieren. Durch den Einsatz von Daemons oder Prozessen sind keine belegten Schleifen oder erheblichen zusätzlichen Aufwand erforderlich.

In den Antworten auf diese Frage finden Sie weitere Informationen zu diesen Lösungen und zur Diskussion des Problems des Abbruchs von Threads.

0
Scott Yeager