这应该非常简单,我很惊讶我在 stackoverflow 上找不到这个问题的答案。
我有一个类似守护程序的程序,需要响应 SIGTERM 和 SIGINT 信号才能与 upstart 良好地配合。我读到,执行此操作的最佳方法是在与主线程不同的线程中运行程序的主循环,并让主线程处理信号。然后,当收到信号时,信号处理程序应该通过设置在主循环中定期检查的哨兵标志来告诉主循环退出。
我已经尝试这样做,但它没有按我预期的方式工作。请参阅下面的代码:
from threading import Thread
import signal
import time
import sys
stop_requested = False
def sig_handler(signum, frame):
sys.stdout.write("handling signal: %s\n" % signum)
sys.stdout.flush()
global stop_requested
stop_requested = True
def run():
sys.stdout.write("run started\n")
sys.stdout.flush()
while not stop_requested:
time.sleep(2)
sys.stdout.write("run exited\n")
sys.stdout.flush()
signal.signal(signal.SIGTERM, sig_handler)
signal.signal(signal.SIGINT, sig_handler)
t = Thread(target=run)
t.start()
t.join()
sys.stdout.write("join completed\n")
sys.stdout.flush()
我通过以下两种方式对此进行了测试:
1)
$ python main.py > output.txt&
[2] 3204
$ kill -15 3204
2)
$ python main.py
ctrl+c
在这两种情况下,我希望将其写入输出:
run started
handling signal: 15
run exited
join completed
在第一种情况下,程序退出,但我看到的是:
run started
在第二种情况下,当按下 ctrl+c 并且程序不退出时,SIGTERM 信号似乎被忽略。
我在这里缺少什么?
问题是,正如中所解释的Python 信号处理程序的执行 https://docs.python.org/3.4/library/signal.html#execution-of-python-signal-handlers:
Python 信号处理程序不会在低级 (C) 信号处理程序内执行。相反,低级信号处理程序会设置一个标志,告诉虚拟机稍后执行相应的 Python 信号处理程序(例如在下一个字节码指令处)
…
纯粹用 C 实现的长时间运行计算(例如对大量文本进行正则表达式匹配)可以不间断地运行任意时间,无论收到任何信号如何。计算完成后将调用 Python 信号处理程序。
你的主线程被阻塞了threading.Thread.join
,这最终意味着它在 C 中被阻止pthread_join
称呼。当然,这不是“长时间运行的计算”,它是系统调用上的一个块……但是,在该调用完成之前,您的信号处理程序无法运行。
并且,在某些平台上pthread_join
将会失败EINTR
在一个信号上,在其他信号上则不会。在linux上,我相信这取决于你选择BSD风格还是默认风格siginterrupt
行为,但默认为否。
所以你对此能做些什么?
嗯,我很确定Python 3.3 中信号处理的变化 https://docs.python.org/3/whatsnew/3.3.html#signal实际上改变了 Linux 上的默认行为,因此升级时您无需执行任何操作;只需在 3.3+ 下运行,您的代码就会按您的预期工作。至少对我来说,OS X 上的 CPython 3.4 和 Linux 上的 3.3 是这样。 (如果我错了,我不确定这是否是 CPython 中的错误,所以你可能想在 python-list 上提出它而不是打开一个问题......)
另一方面,在 3.3 之前,signal
模块绝对不会公开您自己解决此问题所需的工具。因此,如果您无法升级到 3.3,解决方案是等待可中断的事件,例如Condition
or an Event
。子线程在退出之前通知该事件,主线程在加入子线程之前等待该事件。这绝对是hacky。我找不到任何东西可以保证它会有所作为;它恰好适用于 OS X 上的 CPython 2.7 和 3.2 以及 Linux 上的 2.6 和 2.7 的各种版本…
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)