В Python верно, что KeyboardInterrupt
исключения генерируются только в главном потоке каждого процесса. Но, как упоминалось в других ответах, также верно, что метод Thread.join
блокирует вызывающий поток, , включая KeyboardInterrupt
исключения . Вот почему Ctrl + C , похоже, не имеет никакого эффекта: выполнение в главном потоке остается заблокированным в строке thread.join()
.
Таким образом, простое решение вашего вопроса состоит в том, чтобы сначала добавить аргумент времени ожидания к thread.join()
и поместить этот вызов в цикл, который заканчивается при выходе из дочернего потока, чтобы исключения KeyboardInterrupt
могли подниматься после каждого тайм-аута, а во-вторых, сделать дочерний поток daemonic , что означает, что его родитель (основной поток здесь) будет уничтожать его при выходе (только потоки, не являющиеся демонами, не уничтожаются, а присоединяются, когда их родительский выход):
def main():
try:
thread = threading.Thread(target=f, daemon=True) # create a daemon child thread
thread.start()
while thread.is_alive():
thread.join(1) # join shortly to not block KeyboardInterrupt exceptions
except KeyboardInterrupt:
print "Ctrl+C pressed..."
sys.exit(1)
def f():
while True:
pass # do the actual work
Но лучшим решением, если вы управляете кодом дочернего потока, является информирование дочернего потока о том, что он должен завершиться изящно (а не резко, как при первом решении), например, с помощью threading.Event
:
def main():
try:
event = threading.Event()
thread = threading.Thread(target=f, args=(event,))
thread.start()
event.wait() # wait forever but without blocking KeyboardInterrupt exceptions
except KeyboardInterrupt:
print "Ctrl+C pressed..."
event.set() # inform the child thread that it should exit
sys.exit(1)
def f(event):
while not event.is_set():
pass # do the actual work