Python进程在重新启动后停止响应SIGTERM/SIGINT

gdm*_*gdm 3 python freebsd ipc

对于使用监视程序进程运行的一些python进程,我遇到了一个奇怪的问题.

看门狗过程是用Python编写,是家长,并有一个名为函数start_child(名称),它使用subprocess.Popen打开子进程.记录Popen对象,以便监视程序可以使用poll()监视进程,并在需要时最终以terminate()结束.如果孩子意外死亡,监视程序再次调用start_child(name)并记录新的Popen对象.

有7个子进程,所有这些进程也都是python.如果我手动运行任何子项,我可以使用kill发送SIGTERM或SIGINT 并获得我期望的结果(过程结束).

但是,当从看门狗进程运行时,子进程将仅在FIRST信号之后结束.当监视程序重新启动子进程时,新的子进程不再响应SIGTERM或SIGINT.我不知道造成这种情况的原因.

watchdog.py

class watchdog:
    # <snip> various init stuff

    def start(self):
        self.running = true

        kids = ['app1', 'app2', 'app3', 'app4', 'app5', 'app6', 'app7']
        self.processes = {}

        for kid in kids:
            self.start_child(kid)

        self.thread = threading.Thread(target=self._monitor)
        self.thread.start()

        while self.running:
            time.sleep(10)

    def start_child(self, name):
        try:
            proc = subprocess.Popen(name)
            self.processes[name] = proc
        except:
            print "oh no"
        else:
            print "started child ok"

    def _monitor(self):
        while self.running:
            time.sleep(1)
            if self.running:
                for kid, proc in self.processes.iteritems():
                    if proc.poll() is not None: # process ended
                        self.start_child(kid)
Run Code Online (Sandbox Code Playgroud)

所以会发生什么是watchdog.start()启动所有7个进程,如果我发送任何进程SIGTERM,它结束,监视器线程再次启动它.但是,如果我然后发送新进程SIGTERM,它会忽略它.

我应该能够一遍又一遍地向重启的进程发送kill -15.他们为什么重启后会忽略它?

gdm*_*gdm 5

正如这里所解释的:http://blogs.gentoo.org/agaffney/2005/03/18/python_sucks,当Python创建一个新线程时,它会阻止该线程的所有信号(以及线程生成的任何进程).

我使用sigprocmask修复了这个问题,通过ctypes调用.这可能是也可能不是"正确"的方式,但确实有效.

在子进程中,期间__init__:

libc = ctypes.cdll.LoadLibrary("libc.so")
mask = '\x00' * 17 # 16 byte empty mask + null terminator 
libc.sigprocmask(3, mask, None) # '3' on FreeBSD is the value for SIG_SETMASK
Run Code Online (Sandbox Code Playgroud)

  • 混合任何两个fork/exec,线程和信号很难做到.将这三者混合起来是一种灾难. (3认同)