KeyboardInterrupt
例外はPythonのメインスレッドでのみ発生することをどこかで読みました。子スレッドが実行されている間、メインスレッドがブロックされることも読みました。つまり、これは CTRL+C 子スレッドに到達することはできません。私は次のコードを試しました:
def main():
try:
thread = threading.Thread(target=f)
thread.start() # thread is totally blocking (e.g., while True)
thread.join()
except KeyboardInterrupt:
print "Ctrl+C pressed..."
sys.exit(1)
def f():
while True:
pass # do the actual work
この場合、影響はありません CTRL+C 実行時。信号が聞こえないようです。私はこれを間違った方法で理解していますか?使用してスレッドを殺す他の方法はありますか CTRL+C?
問題は、あなたがthread1.join()
を使用していることです。これにより、プログラムは、そのスレッドが継続して終了するまで待機します。
シグナルを受け取るのはシグナルであり、スレッドを持つのはプロセスなので、シグナルは常にメインプロセスによってキャッチされます。
あなたが示すようにそれを行うと、あなたは1つのスレッドを開始し、それが継続するのが終了するまで待つので、基本的にはスレッド機能のない「通常の」アプリケーションを実行しています。
あなたが受け取るメインスレッドを持ちたいなら CTRL+C 参加中にシグナルを送信するには、join()
呼び出しにタイムアウトを追加することで実行できます。
次のコードは機能しているようです(mainを実際に終了させたい場合は、daemon=True
を忘れずに追加してください)。
thread1.start()
while True:
thread1.join(600)
if not thread1.isAlive():
break
Pythonでは、各プロセスのメインスレッドでのみKeyboardInterrupt
例外が発生することは事実です。しかし、他の回答が述べたように、メソッド_Thread.join
_が呼び出しスレッドをブロックすることも真実ですincludeingKeyboardInterrupt
例外。それが理由です Ctrl+C メインスレッドでの実行はthread.join()
の行でブロックされたままです。
したがって、あなたの質問に対する簡単な解決策は、最初にtimeout引数を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
_