2012-02-13 3 views
5

マルチスレッドのPythonプログラムでは、あるスレッドが組み込みのraw_input()を使用してコンソール入力を要求することがあります。 raw_inputプロンプトで、シェルで^ Cと打って(つまりSIGINTシグナルで)、プログラムを閉じることができるようにしたいと思います。しかし、子スレッドがraw_inputを実行しているときに^ Cをタイプすると何も起こりません。私がReturnを押すまで(raw_inputから)KeyboardInterruptは発生しません。例えば^C/KeyboardInterruptを持つ子スレッドでPython raw_input()を中断する

は、以下のプログラムで:

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がメインスレッドに送信され、コンソール上のforkedスレッドブロックが読み込まれている間中断されている(GILを待っている)ためです。メインスレッドは、raw_inputが返ってからGILを取得するまでシグナルハンドラを実行しません。 (私が間違っていると私を修正してください - 私はPythonのスレッド実装の専門家ではありません)

SIGINTの処理を許可しながら、raw_inputのような方法でstdinから読み込む方法はありますかメインスレッドによって、プロセス全体を停止させますか?

[Iは、Mac OS Xといくつかの異なるLinuxesで上記の行動を観察してきました。]


編集:私は上記の根本的な問題をmischaracterizedまし。さらに調査すると、シグナルハンドリングを妨げるのは、join()へのメインスレッドの呼び出しです:Guido van Rossum自身が、the underlying lock acquire in join is uninterruptibleを説明しました。これは、スレッド全体が終了するまで信号が実際に遅延されていることを意味します。つまり、実際にはraw_inputとは何の関係もありません(バックグラウンドスレッドがブロックされているため、結合が完了しません)。

+3

スレッドと中断を単純に結合するのではなく... [boromir.jpg] – JBernardo

答えて

0

この時期には簡単な方法はありません。

1つの方法は、Ctrl-C割り込みがメインスレッド上で実行されるような関数の部分が実行されるようにコードを再編成し、分割することです。キューを使用して実行要求を送信し、同様に結果値を送信します。メインスレッド用に1つの入力キューが必要で、メイン以外のスレッドごとに1つの出力キューが必要です。コーディネートされたメインスレッド出口。当然のことながら、この方法では1つのブロッキング関数しか実行されません。これはあなたが望むものではないかもしれません。

Here's a working example of this ideaコーディネートされたメインスレッドの終了に対して、セマフォの使用が多少誤っています。

3

タイムアウトなしでjoinが呼び出されたときは、中断されませんが、タイムアウトで呼び出されたときには割り込みが可能です。

while my_thread.isAlive(): 
    my_thread.join(5.0) 
関連する問題