【问题标题】:Thread-Safe Signal API in Python 2.7Python 2.7 中的线程安全信号 API
【发布时间】:2017-09-09 06:09:09
【问题描述】:

我有一个多线程程序并且想要捕获 SIGINT。我尝试使用signal 接口,但当程序使用threading 时,它似乎停止执行任何操作。多线程 python 程序的正确信号 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,它通常会起作用。

【问题讨论】:

  • 之前好像遇到过这个问题:stackoverflow.com/questions/25676835/…。有一个提议的解决方案定义了一个 InterruptableThread。
  • 正如您在stackoverflow.com/questions/46161884/… 中评论的那样,这与您在此处看到的问题完全相同。问题是您没有在 try 块中包含线程创建。请参阅我对另一个问题的回答以获得更详细的解释。
  • @JohanL。在捕获信号的上下文中......这里的观察是,如果我们有线程,我们不能单独依赖signal 接口。我们也必须捕获异常。在 Tobe 的回答中查看我的 cmets。

标签: multithreading python-2.7 signals


【解决方案1】:

只有主线程在监听 SIGINT。确保所有线程都在监听 SIGINT 值。

【讨论】:

  • 试过了,但得到了:ValueError: signal only works in main thread。所以你只需要在你的主线程中调用signal.signal()
  • 另外,signal.signal() 的官方 2.7 文档说“启用线程时,只能从主线程调用此函数;尝试从其他线程调用它会导致 ValueError 异常提出。”
  • 感谢您的贡献。为什么拒绝我的编辑?如果您在主线程中有 signal.pause() 并且在所有其他线程中有 try..except ,事情似乎会奏效。虽然我确实注意到,在某些情况下,如果在早期解析阶段出现异常,信号就会丢失。也许解决方案是让 init.py 在 try 块中导入所有内容。虽然如果 Python 有一个“请不要破坏 ctrl-C”标志会更好。
猜你喜欢
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多