为什么使用 threading.Event 会导致 SIGTERM 未被捕获?
我有一个线程Python 守护进程。像任何好的守护进程一样,它想要启动所有工作线程,然后等待,直到被告知终止。正常的终止信号是 SIGTERM,在大多数语言中,我会通过等待事件或互斥体来终止,因此使用 threading.Event 对我来说很有意义。问题是 Python 的 Event
对象和 Unix 信号似乎不能很好地协同工作。
这按预期工作,终止于 SIGTERM
:
import signal
import time
RUN = True
def handle(a, b):
global RUN
print "handled"
RUN = False
signal.signal(signal.SIGTERM, handle)
while RUN:
time.sleep(0.250)
print "Stopping"
但这会导致没有 SIGTERM
被传递(即,除了退出之外,“handled”永远不会被打印):
import signal
import threading
RUN_EVENT = threading.Event()
def handle(a, b):
print "handled"
RUN_EVENT.set()
signal.signal(signal.SIGTERM, handle)
RUN_EVENT.wait()
print "Stopping"
所以我的问题是:
- 我是否以某种方式滥用了threading.Event?
- 如果我不是,除了第一个示例中的轮询和睡眠机制之外还有其他选择吗?
- 另外,如果我不是,为什么使用 threading.Event 会杀死信号处理程序?
I have a threaded Python daemon. Like any good daemon, it wants to launch all of its worker threads, then wait around until it's told to terminate. The normal signal for termination is SIGTERM
, and in most languages I'd hold to terminate by waiting on an event or mutex, so using threading.Event
made sense to me. The problem is that Python's Event
object and Unix signals don't appear to be playing well together.
This works as expected, terminating on SIGTERM
:
import signal
import time
RUN = True
def handle(a, b):
global RUN
print "handled"
RUN = False
signal.signal(signal.SIGTERM, handle)
while RUN:
time.sleep(0.250)
print "Stopping"
but this results in no SIGTERM
being delivered (i.e., quite apart from quitting, "handled" never gets printed):
import signal
import threading
RUN_EVENT = threading.Event()
def handle(a, b):
print "handled"
RUN_EVENT.set()
signal.signal(signal.SIGTERM, handle)
RUN_EVENT.wait()
print "Stopping"
So my question is:
- Am I misusing
threading.Event
in some way? - If I am not, is there an alternative other than the poll-and-sleep mechanism from the first example?
- Also if I am not, why does using
threading.Event
kill the signal handler?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
来自 有关信号的 Python 文档:
我测试了各种
threading
和thread
类,但它们都没有按照您想要的方式工作——这可能是因为 Python 处理信号的方式。然而,在
signal
中,有一个 < code>pause() 函数,该函数会休眠直到进程收到信号。您修改后的示例如下所示:我在 Linux 上检查了它,它有效。如果您的应用程序不使用大量其他信号,我认为它不再归类为轮询和睡眠。
处理
SIGINT
和SIGHUP
也很好,可以正确处理用户中断(通常通过按Ctrl+C
)和用户断开连接(关闭父进程)终端)分别。另请注意
signal.pause()
在 Windows 系统上不可用。From Python documentation on signals:
I tested various
threading
andthread
classes and none of them work the way you want it -- this is probably because of how Python handles signals.In
signal
, however, there is apause()
function that sleeps until a signal is received by the process. Your modified example would look like this:I checked it on Linux, it works. I don't think it classifies as poll-and-sleep anymore if your application doesn't use a lot of other signals.
It's good to handle
SIGINT
andSIGHUP
too, to properly handle user interruption (usually by pressingCtrl+C
) and user disconnection (closing the parent terminal) respectively.Also, note that
signal.pause()
is not available on Windows systems.在 Python 3 中,这有效:
看起来在 Python 2.7 中,只有指定等待间隔时,它才有效:
stop_event.wait(number_of_seconds)
In Python 3, this works:
It looks that in Python 2.7 it works only if you specify wait interval:
stop_event.wait(number_of_seconds)