私はこの簡単なコードを実行しています:
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')
しかし、実行すると印刷されます
$ python prova.py
.
.
^C.
.
.
.
.
.
.
.
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
実際にpythonスレッドは私の無視 Ctrl+C キーボード割り込み、印刷しないReceived Keyboard Interrupt
。どうして?このコードの何が問題になっていますか?
試してみる
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
を使用することでしたが、それはthread
が終了するまでメインプロセスを(KeyboardInterruptを無視して)ブロックするようです。
thread.daemon=True
は、メインプロセスの終了時にスレッドを終了させます。
Ubuntuのソリューションのわずかな変更。
Ericが示唆するようにtread.daemon = Trueを削除し、sleep.loopを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'
_try ... except
_を各スレッドに入れ、さらにsignal.pause()
をtruemain()
に入れるとうまくいきます。
ただし、 import lock に注意してください。これが、Pythonがデフォルトでctrl-Cを解決しない理由です。
私の(ハックな)解決策は、次のようにモンキーパッチ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