为什么在SIGTERM中使用threading.Event结果没被捕获?

Ben*_*ack 16 python events multithreading signals daemon

我有一个线程化的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"
Run Code Online (Sandbox Code Playgroud)

但这导致没有SIGTERM交付(即,除了戒烟,"处理"永远不会被打印):

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"
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. threading.Event在某种程度上滥用了吗?
  2. 如果我不是,除了第一个例子中的poll-and-sleep机制之外还有其他选择吗?
  3. 另外,如果我不是,为什么使用threading.Event杀死信号处理程序?

Dzi*_*inX 15

Python文档信号:

虽然就Python用户而言,Python信号处理程序是异步调用的,但它们只能出现在Python解释器的"原子"指令之间.这意味着在纯C中实现的长计算期间到达的信号(例如大文本上的正则表达式匹配)可能会延迟一段任意时间.

我测试了各种类threadingthread类,它们都没有按照你想要的方式工作 - 这可能是因为Python处理信号的方式.

signal,然而,有一种pause()该休眠,直到一个信号由处理接收的功能.您修改过的示例如下所示:

import signal

RUN = True

def handle(a, b):
    global RUN
    print "handled"
    RUN = False

signal.signal(signal.SIGTERM, handle)
while RUN:
    signal.pause()
print "Stopping"
Run Code Online (Sandbox Code Playgroud)

我在Linux上检查过,它确实有效.如果您的应用程序不使用大量其他信号,我认为它不再归类为轮询和睡眠.

  • 这是否意味着处理信号的唯一方法是将主线程(父线程)专用于捕获信号(通过阻塞'signal.pause()')?这意味着主线程不再有用了.换句话说,你不能拥有一个主/工模型(两个线程相互通信),但是你需要一个主/工人+工人模型(两个工人互相交谈,主人不做任何事情. (3认同)