8

マルチスレッドの Python プログラムでは、1 つのスレッドが組み込みのraw_input()を使用してコンソール入力を要求することがあります。raw_input プロンプトが表示されているときに、シェルで ^C と入力して (つまり、SIGINT シグナルを使用して) プログラムを終了できるようにしたいと考えています。ただし、子スレッドが raw_input を実行している場合、^C と入力しても何も起こりません。Return を押す (raw_input を離れる) まで、KeyboardInterrupt は発生しません。

たとえば、次のプログラムでは:

import threading

class T(threading.Thread):
    def run(self):
        x = raw_input()
        print x

if __name__ == '__main__':
    t = T()
    t.start()
    t.join()

^C と入力しても、入力が終了するまで何も起こりません。ただし、呼び出すだけの場合T().run()(つまり、シングルスレッドの場合: メインスレッドで raw_input を実行するだけ)、^C はすぐにプログラムを閉じます。

おそらく、これは SIGINT がメイン スレッドに送信され、コンソール上でフォークされたスレッド ブロックが読み取られている間、メイン スレッドが中断されている (GIL を待機している) ためです。メイン スレッドは、raw_input が返された後に GIL を取得するまで、シグナル ハンドラを実行できません。(これについて間違っている場合は訂正してください。私は Python のスレッド実装の専門家ではありません。)

SIGINT をメインスレッドで処理できるようにしながら、raw_input のような方法で stdin から読み取り、プロセス全体をダウンさせる方法はありますか?

[Mac OS X といくつかの異なる Linux で上記の動作を確認しました。]


編集:上記の根本的な問題を誤解しています。さらに調査すると、join()シグナル処理を妨げているのはメイン スレッドの呼び出しです。これは、スレッド全体が終了するまでシグナルが実際に延期されていることを意味します。したがって、これは実際にはまったく関係ありませんraw_input(結合が完了しないようにバックグラウンド スレッドがブロックされているという事実だけです)。

4

2 に答える 2

6

join がタイムアウトなしで呼び出された場合は中断できませんが、タイムアウト付きで呼び出された場合は中断可能です。任意のタイムアウトを追加して、while ループに入れてみてください。

while my_thread.isAlive():
    my_thread.join(5.0)
于 2012-03-20T16:29:39.520 に答える
1

これを回避する簡単な方法は本当にありません。

Ctrl-C1 つのアプローチは、割り込み可能性を必要とする関数の一部がメイン スレッドで実行されるように、コードを再編成して分割することです。キューを使用して実行リクエストを送信し、同様に結果値を送信します。メイン スレッド用に 1 つの入力キューと、非メイン スレッドごとに 1 つの出力キューが必要です。調整されたメインスレッド出口。明らかに、この方法では常に 1 つのブロッキング関数のみが実行されますが、これは望ましくない場合があります。

これは、調整されたメイン スレッドの出口にセマフォを少しひねった使い方をした、このアイデアの実例です。

于 2012-02-14T00:39:33.543 に答える