Python中的SIGTERM处理程序在子进程中未激活

0 投票
2 回答
509 浏览
提问于 2025-04-18 10:29

我想在我的代码中优雅地释放一些昂贵的系统资源,使用事件处理器来实现。问题是,这个事件处理器是在一个分叉的子进程中注册的(是的,我必须把事件处理器放在子进程里,因为资源是在分叉后分配的),我希望当父进程结束时,子进程也能终止。但是,代码的表现并没有如我所预期的那样。

这里有一个可以运行的示例:

import time
import os
import signal

PRCTL=None
# get prctl from libc
def getPRCTL():
    global PRCTL
    if PRCTL is None:
        import ctypes
        PRCTL = ctypes.CDLL("libc.so.6")["prctl"]

    return PRCTL

def dieWithParent():
    prctl = getPRCTL()
    prctl(1, signal.SIGTERM)    # 1 = PR_SET_PDEATHSIG

def foo():
    print "In foo."

    def handler(signo, frame):
        print "Handler is activated."

    signal.signal(signal.SIGTERM, handler)

    time.sleep(10)    # in case sub-process terminates first.

if __name__ == '__main__':
    dieWithParent()
    pid = os.fork()
    if 0 == pid:
        foo()
    else:
        print "Subprocess spawned."
        print "dying..."

这段代码做了以下几件事:

  1. 指示操作系统将父进程的死亡信号转为SIGTERM信号;
  2. 创建一个子进程;
  3. 如果是子进程,就注册信号处理器并等待父进程的结束。

在我的平台上,输出结果是

$ python main.py
In foo.
Subprocess spawned.
dying...

看起来处理器并没有被激活。

我的代码或理解上有什么问题吗?

我这边的配置是

2.6.18-238.el5 x86_64 Python 2.6

任何提示都非常感谢,谢谢!

2 个回答

-1

如果你是在尝试写一个守护进程(daemon),那么你应该了解一下双重分叉(double forking)。

比如说,你可以参考这个链接: http://code.activestate.com/recipes/66012-fork-a-daemon-process-on-unix/

2

来自 prctl

PR_SET_PDEATHSIG(自 Linux 2.1.57 起)是用来设置调用进程的父进程死亡信号的。这个信号可以是一个在 1 到 maxsig 范围内的信号值,或者是 0(表示不设置)。当调用进程的父进程死掉时,它会收到这个信号。这个值在调用 fork(创建子进程)时会被清除(2),并且(自 Linux 2.4.36 / 2.6.23 起)在执行设置用户 ID 或组 ID 的程序时也会被清除。

所以,简单来说,你确保你的父进程会在它的父进程死掉时也死掉,但这对你的子进程没有影响。

如果你添加:

dieWithParent()

在你创建子进程之后,这样做就能正常工作了。

撰写回答