2017-09-09 15 views
-3

私はマルチスレッドのプログラムを持っており、SIGINTを捕まえたいと思っています。私はsignalインターフェイスを使ってみましたが、プログラムがthreadingを使用しているときに何もしないようです。マルチスレッドPythonプログラムの正しいシグナルAPIは何ですか?Python 2.7のスレッドセーフシグナルAPI

import signal 
import sys 
import threading 
import os 

# register my Ctrl-C handler   
def signal_handler(signal, frame): 
    print('Signal.') 
    os._exit(0) 
signal.signal(signal.SIGINT, signal_handler) 

# stop the main thread 
lock = threading.Lock() 
with lock: 
    threading.Condition(lock).wait() 

私は、Python 2.7.6を使用していますし、私のpip freezeは言う:

Flask==0.10.1 
Jinja2==2.9.6 
Mako==1.0.7 
MarkupSafe==1.0 
PAM==0.4.2 
Pillow==2.3.0 
PyYAML==3.12 
Saltscaffold==3.0.5 
Twisted-Core==13.2.0 
Twisted-Web==13.2.0 
Werkzeug==0.9.4 
adium-theme-ubuntu==0.3.4 
apt-xapian-index==0.45 
argparse==1.2.1 
arrow==0.10.0 
astroid==1.0.1 
binaryornot==0.4.4 
blinker==1.3 
chardet==3.0.4 
click==6.7 
colorama==0.2.5 
command-not-found==0.3 
cookiecutter==1.5.1 
debtagshw==0.1 
defer==1.0.6 
dirspec==13.10 
duplicity==0.6.23 
future==0.16.0 
gevent==1.0 
greenlet==0.4.2 
gunicorn==17.5 
html5lib==0.999 
httplib2==0.8 
itsdangerous==0.22 
jinja2-time==0.2.0 
lockfile==0.8 
logilab-common==0.61.0 
lxml==3.3.3 
nose==1.3.7 
oauthlib==0.6.1 
oneconf==0.3.7.14.04.1 
pexpect==3.1 
piston-mini-client==0.7.5 
poyo==0.4.1 
pyOpenSSL==0.13 
pycrypto==2.6.1 
pycups==1.9.66 
pygobject==3.12.0 
pyinotify==0.9.4 
pylint==1.1.0 
pyserial==2.6 
pysmbc==1.0.14.1 
python-apt==0.9.3.5ubuntu2 
python-dateutil==2.6.1 
python-debian==0.1.21-nmu2ubuntu2 
pyxdg==0.25 
reportlab==3.0 
requests==2.2.1 
sessioninstaller==0.0.0 
simplejson==3.3.1 
six==1.10.0 
software-center-aptd-plugins==0.0.0 
ssh-import-id==3.21 
system-service==0.1.6 
unity-lens-photos==1.0 
urllib3==1.7.1 
vboxapi==1.0 
wheel==0.24.0 
whichcraft==0.4.1 
wsgiref==0.1.2 
xdiagnose==3.6.3build2 
zope.interface==4.0.5 

は、私も私のメインスレッドでsignal.pause()をやってみましたが、それはまだ動作しません:

import threading, sys, signal, os 

stderr_lock = threading.Lock() 

def Log(module, msg): 
    with stderr_lock: 
     sys.stderr.write("%s: %s\n" % (module, msg)) 

class My_Thread(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
     Log("Init", "Initing.") 
     self.start() 
    def run(self): 
     while True: 
      Log("Run", "Running.") 

for i in range(100): 
    My_Thread() 

# trap ctrl-C in main thread 
def handler(signal, frame): 
    print "GOT SIGINT!" 
    os._exit(0) 
signal.signal(signal.SIGINT, handler) 
signal.pause() 

奇妙なことに、通常スレッドの数を100から87に減らすと機能します。

+0

これまでにこの問題が発生しているようです:https://stackoverflow.com/questions/25676835/signal-handling-in-multi-threaded-python InterruptableThreadを定義する提案されたソリューションがあります。 –

+0

https://stackoverflow.com/questions/46161884/python-2-7-how-to-catch-keyboard-interrupt-in-program-with-more-than-25-threads/でコメントしています。これは正確ですあなたがそこに見るのと同じ問題です。問題は、スレッド作成を 'try'ブロックに含めないことです。もっと精巧な説明のために私の答えを他の質問に見てください。 – JohanL

+0

@ JohanL。シグナルをキャッチするコンテキストでは、ここには、スレッドがあれば 'signal'インターフェースだけに依存することができません。例外をキャッチする必要があります。戸部の答えに対する私のコメントを見てください。 –

答えて

1

メインスレッドだけがSIGINTを待ち受けています。すべてのスレッドがSIGINT値をリッスンしていることを確認してください。

+0

それを試しましたが、「ValueError:シグナルはメインスレッドでのみ動作します」。だからあなたはメインスレッドで 'signal.signal()'を呼び出さなければなりません。 –

+0

また、 'signal.signal()'の公式の2.7文書では、 "スレッドが有効な場合、この関数はメインスレッドからしか呼び出せず、他のスレッドから呼び出そうとするとValueError例外が発生します。 –

+0

私はあなたの貢献に感謝します。なぜ私の編集を拒否したのですか?メインスレッドでsignal.pause()を、他のすべてのスレッドでtry..exceptを使用していれば、動作するようです。初期の解析段階で例外があると、信号が失われることがあることに気付いたことがあります。おそらく解決策は、tryブロック内のすべてを__init__.pyでインポートすることです。 Pythonが "ctrl-C please"フラグを壊していない場合は、はるかに良いでしょう。 –