私はpythonプログラムを書いています。メイン関数で、継続的に実行されるスレッドを開始しています。スレッドを開始した後、メイン関数は while ループに入り、ユーザー入力を継続的に受け取ります。子スレッドで例外が発生した場合は、メイン関数も終了したいと考えています。それを行う最善の方法は何ですか?
前もって感謝します
私はpythonプログラムを書いています。メイン関数で、継続的に実行されるスレッドを開始しています。スレッドを開始した後、メイン関数は while ループに入り、ユーザー入力を継続的に受け取ります。子スレッドで例外が発生した場合は、メイン関数も終了したいと考えています。それを行う最善の方法は何ですか?
前もって感謝します
親を「制御」するスレッドを持つことは、良い習慣ではありません。メインスレッドが開始するスレッドを管理/監視/制御する方が理にかなっています。
したがって、私の提案は、メイン スレッドが 2 つのスレッドを開始することです。既にあるスレッドは、ある時点で例外を終了/発生させ、もう 1 つはユーザー入力を読み取ります。メインスレッドはjoin
、前者が終了するのを待ち ( s)、終了すると終了します。
from threading import Thread
import time
class ThreadA(Thread):
def run(self):
print 'T1: sleeping...'
time.sleep(4)
print 'T1: raising...'
raise RuntimeError('bye')
class ThreadB(Thread):
def __init__(self):
Thread.__init__(self)
self.daemon = True
def run(self):
while True:
x = raw_input('T2: enter some input: ')
print 'GOT:', x
t1 = ThreadA()
t2 = ThreadB()
t1.start()
t2.start()
t1.join() # wait for t1 to finish/raise
print 'done'
ThreadB はデーモンであるため、明示的に停止させたり、参加させたりする必要はありません。メインスレッドが終了すると、それも終了します。
IMO、信号のような低レベルのものに頼る必要はありません。このソリューションでは、使用する必要さえありませんtry-except
(ただし、正常に終了させるためにtry-except
inが必要になる場合があります)。ThreadA
Python では、シグナルモジュールを介してこのシステム コールにアクセスできるため、シグナル ハンドラを登録して、SIGINT
好きなことを行うことができます。SIGINT
ちなみに、デフォルトのハンドラーは単純にKeyboardInterrupt
例外を発生させるため、シグナルを使用したくない場合は、プログラム全体を try/except 構造に配置して、多かれ少なかれ同じ効果を得ることができます。子スレッドでのクラッシュ時にメイン スレッドを停止したいので、while ループ全体をexcept Exception:
try-except ブロックに入れるだけです。
これは機能するはずですが、いくつかの背景情報-Pythonのシグナルモジュールのドキュメントには、複数のスレッドが実行されている場合、メインスレッド(つまり、プロセスの開始時に作成されたスレッド)のみがシグナルを受信すると明示的に記載されています(メインスレッドのシグナル)。そのため、シグナル ハンドラは 1 つのスレッドでのみ実行され、すべてのスレッドでは実行されません。シグナルに応答してすべてのスレッドを停止するには、メイン スレッドのシグナル ハンドラが他の子スレッドに停止メッセージを伝える必要があります。これはさまざまな方法で実行できますが、最も簡単な方法は、すべての子スレッドも参照を保持するブール変数の値をメイン スレッドで反転させることです。