2017-09-09 8 views
-3

나는 멀티 스레드 프로그램을 가지고 있으며 SIGINT를 잡으려고합니다. signal 인터페이스를 사용해 보았지만 프로그램에서 threading을 사용할 때 아무 것도하지 않는 것처럼 보입니다. 멀티 스레드 파이썬 프로그램에 올바른 신호 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() 

나는 파이썬 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. 신호 잡기의 컨텍스트에서 ... 여기서 관찰은 스레드가있는 경우에만 '신호'인터페이스에만 의존 할 수 없다는 것입니다. 예외도 잡아야합니다. 도베의 대답에 대한 내 의견을 참조하십시오. –

답변

1

주 스레드 만 SIGINT를 듣고 있습니다. 모든 스레드가 SIGINT 값을 청취하고 있는지 확인하십시오.

+0

시도했지만, : ValueError : 신호는 주 스레드에서만 작동합니다. 따라서 메인 쓰레드에서만'signal.signal()'을 호출해야한다. –

+0

또한,'signal.signal()'에 대한 공식 2.7 문서에서는 "스레드가 활성화되면이 함수는 메인 스레드에서만 호출 할 수 있으며 다른 스레드에서 호출하려고하면 ValueError 예외가 발생합니다." –

+0

귀하의 기고에 감사드립니다. 왜 내 편집을 거부 했습니까? 상황이 주 스레드에서 signal.pause()가 있고 다른 모든 스레드에서 try..except가 있으면 작동하는 것 같습니다. 초기 파싱 단계에서 예외가있는 경우 신호가 손실되는 경우가 있습니다. 아마도 해결책은 try 블록 내에있는 모든 것을 __init__.py 가져 오기하는 것입니다. 파이썬이 "ctrl-C please break"플래그를 가지고 있다면 훨씬 더 좋을 것이다. –