2

以下の Python プログラムは、1 つのスレッドを開始し、メイン スレッドでアクションを実行し続けます。メイン スレッド全体を try-except ブロックでラップして、例外が発生した場合に実行中のすべてのスレッドを破棄できるようにします。

Python 2.7.5 を使用してスクリプトを実行し、プログラムの実行中に任意の時点で KeyboardInterrupt を呼び出すと、例外はトリガーされますが、キャッチされません。プログラムは引き続き実行されます。

$ python test.py 
Running server ...
Searching for servers ...
^CTraceback (most recent call last):
  File "test.py", line 50, in <module>
    main()
  File "test.py", line 40, in main
    app_main()
  File "test.py", line 35, in app_main
    searchservers()
  File "test.py", line 26, in searchservers
    time.sleep(0.0005)
KeyboardInterrupt

main()例外が発生したときに出力された行がありません。


コード

import time
import threading

thread_pool = []
running = False

def stop():
    global running
    running = False

def runserver():
    print "Running server ..."

    global running
    running = True

    while running:
        time.sleep(0.07)

def searchservers():
    print "Searching for servers ..."

    for i in xrange(256):
        for j in xrange(256):
            time.sleep(0.0005)

def app_main():
    server = threading.Thread(target=runserver)
    thread_pool.append(server)
    server.start()

    time.sleep(0.1)

    searchservers()
    stop()

def main():
    try:
        app_main()
    except Exception as exc:
        stop()
        print "%s occured, joining all threads..." % exc.__class__.__name__
        for thread in thread_pool:
            thread.join()

        raise exc

if __name__ == "__main__":
    main()

KeyboardInterrupt がキャッチされないのはなぜですか? スレッド化されたプログラムで例外をキャッチし、プロセス全体を破棄する適切な方法は何ですか?

4

1 に答える 1

3

KeyboardInterrupt特別な例外です。MemoryErrorGeneratorExitおよびのように、基本クラスから派生しSystemExitません。Exception

したがって、キャッチするだけExceptionでは十分ではありません。通常は明示的にキャッチします:

except (Exception, KeyboardInterrupt) as exc:

ただし、スレッドで例外をキャッチしようとしています。スレッドには独自の個別のスタックがあります。メインスレッドのスタックでスローされた例外をキャッチすることはできません。そのスレッドで例外をキャッチする必要があります:

def runserver():
    print "Running server ..."

    global running
    running = True

    try:    
        while running:
            time.sleep(0.07)
    except (Exception, KeyboardInterrupt) as exc:
        print "Error in the runserver thread"

これを一般的な方法で処理し、例外をメインスレッドに「渡す」には、ある種のスレッド間通信が必要です。その完全な解決策については、Python の呼び出し元スレッドでスレッドの例外をキャッチするを参照してください。

于 2013-10-26T09:20:40.107 に答える