2009-09-28 22 views

Odpowiedz

33

Jeśli wszystkie wątki poza głównymi są demony, najlepszym rozwiązaniem jest ogólnie thread.interrupt_main() - każdy wątek może go użyć do podniesienia KeyboardInterrupt w głównym wątku, który można normalnie prowadzić do względnie czysty wyjściu z głównego wątku (w tym wywoływanie finalizatorów w głównym wątku, itp.).

Oczywiście, jeśli skutkiem jakiegoś wątku non-demon utrzymując cały proces przy życiu, trzeba nawiązanie z os._exit jak zaleca Mark - ale ja widzę, że w ostateczności (niby jak kill -9; -), ponieważ kończy się to dość brutalnie (finalizatory nie działają, w tym try/finally bloków, with bloków, atexit funkcji, itp.).

+0

Twój link jest martwy. – OrangeDog

28

Krótka odpowiedź: użyj os._exit.

Długa odpowiedź z przykładu:

I szarpnął i nieco zmodyfikowany prosty przykład wątków z a tutorial on DevShed:

import threading, sys, os 

theVar = 1 

class MyThread (threading.Thread): 

    def run (self): 

     global theVar 
     print 'This is thread ' + str (theVar) + ' speaking.' 
     print 'Hello and good bye.' 
     theVar = theVar + 1 
     if theVar == 4: 
      #sys.exit(1) 
      os._exit(1) 
     print '(done)' 

for x in xrange (7): 
    MyThread().start() 

Jeśli trzymać sys.exit(1) wykomentowane skrypt umrze po trzecim wypisuje gwintów. Jeśli używasz sys.exit(1) i komentujesz os._exit(1), trzeci wątek ma , a nie drukuj (done), a program przechodzi przez wszystkie siedem wątków.

os._exit "zwykle powinien być używany tylko w procesie potomnym po rozwidleniu()" - a oddzielny wątek jest wystarczająco blisko do tego celu. Zauważ, że na tej stronie podręcznika znajduje się kilka wymienionych wartości zaraz po os._exit, a powinieneś preferować te jako argumenty do os._exit zamiast prostych liczb takich jak użyłem w powyższym przykładzie.

11

Korzystanie z thread.interrupt_main() może nie pomóc w niektórych sytuacjach. KeyboardInterrupt s są często używane w aplikacjach linii poleceń, aby wyjść z bieżącego polecenia lub oczyścić linię wejściową.

Ponadto, os._exit zabije proces natychmiast, bez uruchamiania bloków finally w kodzie, co może być niebezpieczne (pliki i połączenia nie zostaną na przykład zamknięte).

Rozwiązaniem, które znalazłem, jest zarejestrowanie procedury obsługi sygnału w wątku głównym, który podnosi niestandardowy wyjątek. Użyj wątku tła, aby wystrzelić sygnał.

import signal 
import os 
import threading 
import time 


class ExitCommand(Exception): 
    pass 


def signal_handler(signal, frame): 
    raise ExitCommand() 


def thread_job(): 
    time.sleep(5) 
    os.kill(os.getpid(), signal.SIGUSR1) 


signal.signal(signal.SIGUSR1, signal_handler) 
threading.Thread(target=thread_job).start() # thread will fire in 5 seconds 
try: 
    while True: 
     user_input = raw_input('Blocked by raw_input loop ') 
     # do something with 'user_input' 
except ExitCommand: 
    pass 
finally: 
    print('finally will still run') 

Powiązane pytania:

Powiązane problemy