Threading игнорирует исключение KeyboardInterrupt
Я запускаю этот простой код:
import threading, time
class reqthread ( threading.Thread ):
def __init__ (self):
threading.Thread.__init__(self)
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'
Но когда я запускаю его, он печатает
$ python prova.py
`
.
.
^C.
.
.
.
.
.
.
.
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
`
Фактически поток python игнорирует мое прерывание клавиатуры Ctrl + C и не печатает Received Keyboard Interrupt
. Зачем? Что не так с этим кодом?
Ответы
Ответ 1
Попробуйте
try:
thread=reqthread()
thread.daemon=True
thread.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
print '\n! Received keyboard interrupt, quitting threads.\n'
Без вызова time.sleep
основной процесс выскочит из блока try...except
слишком рано, поэтому KeyboardInterrupt
не будет обнаружен. Моя первая мысль заключалась в использовании thread.join
, но это, по-видимому, блокирует основной процесс (игнорируя KeyboardInterrupt), пока не закончится thread
.
thread.daemon=True
заставляет поток прекращаться, когда заканчивается основной процесс.
Ответ 2
Чтобы подвести итоги, рекомендованные в комментариях, для меня хорошо работает следующее:
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()
Ответ 3
Небольшая модификация решения ubuntu.
Удаление tread.daemon = Истина, предложенная Эриком, и замена спального цикла на 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'
Ответ 4
Мое решение (hacky) для monkey-patch Thread.join()
:
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
Ответ 5
Помещение try ... except
в каждом потоке, а также signal.pause()
в true main()
работает для меня.
Следите за блокировкой импорта. Я предполагаю, что Python по умолчанию не разрешает ctrl-C.