threading ignora eccezione KeyboardInterrupt
-
05-10-2019 - |
Domanda
Io corro questo semplice codice:
import threading, time
class reqthread(threading.Thread):
def run(self):
for i in range(0, 10):
time.sleep(1)
print('.')
try:
thread = reqthread()
thread.start()
except (KeyboardInterrupt, SystemExit):
print('\n! Received keyboard interrupt, quitting threads.\n')
Ma quando l'eseguo, stampa
$ python prova.py
.
.
^C.
.
.
.
.
.
.
.
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
In realtà discussione python ignorare la mia Ctrl + C Tastiera di interrupt e non stampa Received Keyboard Interrupt
. Perché? Cosa c'è di sbagliato con questo codice?
Soluzione
Prova
try:
thread=reqthread()
thread.daemon=True
thread.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
Senza la chiamata al time.sleep
, il processo principale sta saltando fuori dal blocco try...except
troppo presto, in modo che il KeyboardInterrupt
non viene catturato. Il mio primo pensiero è stato quello di utilizzare thread.join
, ma che sembra bloccare il processo principale (ignorando KeyboardInterrupt) fino a quando il thread
è finito.
thread.daemon=True
causa il thread di terminare quando finisce il processo principale.
Altri suggerimenti
Per riassumere le modifiche raccomandate nella il commenti , il seguente funziona bene per me:
try:
thread = reqthread()
thread.start()
while thread.isAlive():
thread.join(1) # not sure if there is an appreciable cost to this.
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
sys.exit()
lieve modifica della soluzione di ubuntu.
La rimozione tread.daemon = true come suggerito da Eric e sostituendo il ciclo notte da signal.pause ():
import signal
try:
thread=reqthread()
thread.start()
signal.pause() # instead of: while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
Il mio (hacky) soluzione è quella di scimmia-patch Thread.join()
in questo modo:
def initThreadJoinHack():
import threading, thread
mainThread = threading.currentThread()
assert isinstance(mainThread, threading._MainThread)
mainThreadId = thread.get_ident()
join_orig = threading.Thread.join
def join_hacked(threadObj, timeout=None):
"""
:type threadObj: threading.Thread
:type timeout: float|None
"""
if timeout is None and thread.get_ident() == mainThreadId:
# This is a HACK for Thread.join() if we are in the main thread.
# In that case, a Thread.join(timeout=None) would hang and even not respond to signals
# because signals will get delivered to other threads and Python would forward
# them for delayed handling to the main thread which hangs.
# See CPython signalmodule.c.
# Currently the best solution I can think of:
while threadObj.isAlive():
join_orig(threadObj, timeout=0.1)
else:
# In all other cases, we can use the original.
join_orig(threadObj, timeout=timeout)
threading.Thread.join = join_hacked
Mettere il try ... except
in ogni thread e anche un signal.pause()
in true main()
funziona per me.
Attenzione per blocco importazione però. Sto indovinando questo è il motivo per cui Python non risolve ctrl-C per impostazione predefinita.