如何使子进程在父进程退出后终止?

249
假设我有一个进程会生成一个子进程,现在无论何种原因导致父进程退出(正常或异常退出、被kill掉、^C、断言失败或任何其他原因),我都希望子进程能够随之退出。如何正确实现这个功能?
stackoverflow上的一些类似问题:
stackoverflow上一些关于Windows系统的类似问题:
24个回答

0

我已经通过环境变量将父进程 ID 传递给了子进程,然后从子进程定期检查 /proc/$ppid 是否存在。


父进程的pid可能在下一次检查时已经被重用,因此不是完全健壮的。 - undefined

0

我找到了两个解决方案, 但都不是完美的。

1.接收SIGTERM信号后通过kill(-pid)杀死所有子进程。
显然,这个解决方案无法处理"kill -9",但对于大多数情况来说它确实可以工作并且非常简单,因为它不需要记住所有子进程。


    var childProc = require('child_process').spawn('tail', ['-f', '/dev/null'], {stdio:'ignore'});

    var counter=0;
    setInterval(function(){
      console.log('c  '+(++counter));
    },1000);

    if (process.platform.slice(0,3) != 'win') {
      function killMeAndChildren() {
        /*
        * On Linux/Unix(Include Mac OS X), kill (-pid) will kill process group, usually
        * the process itself and children.
        * On Windows, an JOB object has been applied to current process and children,
        * so all children will be terminated if current process dies by anyway.
        */
        console.log('kill process group');
        process.kill(-process.pid, 'SIGKILL');
      }

      /*
      * When you use "kill pid_of_this_process", this callback will be called
      */
      process.on('SIGTERM', function(err){
        console.log('SIGTERM');
        killMeAndChildren();
      });
    }


同样的方法,如果您在某个地方调用process.exit,您可以像上面提到的那样安装'exit'处理程序。 注意:Ctrl+C和突然崩溃已经被操作系统自动处理为杀死进程组,因此不再需要额外处理。
2.使用chjj/pty.js来生成附加控制终端的进程。 无论如何都要杀死当前进程,甚至是kill -9,所有子进程也将自动被杀死(由操作系统?)。我猜这是因为当前进程持有终端的另一端,所以如果当前进程消失,子进程将收到SIGPIPE信号并死亡。

    var pty = require('pty.js');

    //var term =
    pty.spawn('any_child_process', [/*any arguments*/], {
      name: 'xterm-color',
      cols: 80,
      rows: 30,
      cwd: process.cwd(),
      env: process.env
    });
    /*optionally you can install data handler
    term.on('data', function(data) {
      process.stdout.write(data);
    });
    term.write(.....);
    */


-1

虽然已经过去了7年,但我刚遇到这个问题,因为我正在运行SpringBoot应用程序,在开发期间需要启动webpack-dev-server,并在后端进程停止时将其关闭。

我尝试使用Runtime.getRuntime().addShutdownHook,但它在Windows 10上工作正常,但在Windows 7上不起作用。

我改用一个专用线程,等待进程退出或InterruptedException,这似乎在两个Windows版本上都可以正确工作。

private void startWebpackDevServer() {
    String cmd = isWindows() ? "cmd /c gradlew webPackStart" : "gradlew webPackStart";
    logger.info("webpack dev-server " + cmd);

    Thread thread = new Thread(() -> {

        ProcessBuilder pb = new ProcessBuilder(cmd.split(" "));
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.directory(new File("."));

        Process process = null;
        try {
            // Start the node process
            process = pb.start();

            // Wait for the node process to quit (blocking)
            process.waitFor();

            // Ensure the node process is killed
            process.destroyForcibly();
            System.setProperty(WEBPACK_SERVER_PROPERTY, "true");
        } catch (InterruptedException | IOException e) {
            // Ensure the node process is killed.
            // InterruptedException is thrown when the main process exit.
            logger.info("killing webpack dev-server", e);
            if (process != null) {
                process.destroyForcibly();
            }
        }

    });

    thread.start();
}

因为问题涉及到Unix,如标签和其他答案所示,所以我给你一个踩的。此外,如果在Linux下使用SIGKILL终止java/jvm进程,这种方法很可能无法停止该进程。 - undefined

-1
如果父进程死亡,孤儿进程的PPID会变为1 - 您只需要检查自己的PPID。 从某种意义上说,这是上面提到的轮询。 以下是用于此的shell代码片段:
check_parent () {
      parent=`ps -f|awk '$2=='$PID'{print $3 }'`
      echo "parent:$parent"
      let parent=$parent+0
      if [[ $parent -eq 1 ]]; then
        echo "parent is dead, exiting"
        exit;
      fi
}


PID=$$
cnt=0
while [[ 1 = 1 ]]; do
  check_parent
  ... something
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接