在Java中处理SIGCHLD信号

时间:2015-01-11 10:09:37

标签: java linux bash signals

我有一个Java进程,(重新)启动一个Linux进程,它产生两个守护进程的子进程并死掉。 (它是HAProxy的包装器,它被配置为具有2个进程的守护进程)

每次重新启动时,进程表都有两个Zombie进程。 为了防止这些僵尸,我实施了以下内容:

final static SignalHandler _signalHandler = new SignalHandler() {

    @Override
    public void handle(Signal signal) {
        LOG.info("Received signal: {}",signal.getName());
    }
};

public HaproxyWrapper() {
    Signal.handle(new Signal("CHLD"), _signalHandler);
    LOG.info("Registered SIGCHLD signal handler");
}

我看到了注册的SIGCHLD'登录输出,但从来没有收到信号:SIGCHLD'。

我这样做错了吗?

或者,'最简单的事情可能会起作用。 - 我可以创建一个名为start_haproxy.sh的shell脚本,它将调用haproxy并处理SIGCHLD。如何在bash中处理SIGCHLD? (句柄 - >忽略)

感谢。

2 个答案:

答案 0 :(得分:2)

我很确定Java已经忽略了SIGCLD,这就是为什么你无法捕获它。只有正在运行的进程才会收到此信号,如果您Process.waitFor(),您将收到通知,告知您的子进程已经死亡。

僵尸进程是那些无法杀死的进程,即它们应该在它们应该死后继续存在,通常是由于操作系统中的问题。我怀疑你担心孤儿进程,即当你有一个父母去世的过程时。

防止这种情况的最简单方法是让你的父母等待它的孩子死去。

BTW守护程序进程通常作为孤立进程运行。你确定这确实是个问题吗?

答案 1 :(得分:1)

如果其父级仍然存在但尚未为该子级执行wait,则存在僵尸进程。为什么Java不这样做,我不知道。如果父母退出,孩子只需重新参与PID 1(init);在这种情况下,它不能成为僵尸。这是使用双重分叉的一个原因(确保守护程序一旦启动就重新定位到init,因为它的直接父级已经退出)。

简单的方法是使用正确守护进程的shell脚本。根据您的Linux发行版,您可能已经有一个实用程序可以执行此操作(例如start-stop-daemon。否则,您需要类似

的内容
#/bin/bash
(nohup /path/to/program 0<&- &>/dev/null &)&

执行必要的双叉。有一种更长但更彻底的方法here