假设我有一个进程,它只生成一个子进程。现在,当父进程由于某种原因(正常或不正常,通过kill, ^C,断言失败或其他任何原因)退出时,我希望子进程死亡。如何正确地做到这一点?
关于stackoverflow的一些类似问题:
(前面问过)当父进程退出的时候,我怎么能让子进程退出呢? (稍后问)用fork()创建的子进程会在父进程被杀死时自动被杀死吗?
关于Windows的stackoverflow也有类似的问题:
如何在Windows中自动销毁子进程? 当父进程被杀死时,杀死子进程
假设我有一个进程,它只生成一个子进程。现在,当父进程由于某种原因(正常或不正常,通过kill, ^C,断言失败或其他任何原因)退出时,我希望子进程死亡。如何正确地做到这一点?
关于stackoverflow的一些类似问题:
(前面问过)当父进程退出的时候,我怎么能让子进程退出呢? (稍后问)用fork()创建的子进程会在父进程被杀死时自动被杀死吗?
关于Windows的stackoverflow也有类似的问题:
如何在Windows中自动销毁子进程? 当父进程被杀死时,杀死子进程
当前回答
受到这里另一个答案的启发,我提出了以下全posix解决方案。一般思想是在父进程和子进程之间创建一个中间进程,其目的只有一个:注意父进程何时死亡,并显式地终止子进程。
当子进程中的代码无法修改时,这种解决方案非常有用。
int p[2];
pipe(p);
pid_t child = fork();
if (child == 0) {
close(p[1]); // close write end of pipe
setpgid(0, 0); // prevent ^C in parent from stopping this process
child = fork();
if (child == 0) {
close(p[0]); // close read end of pipe (don't need it here)
exec(...child process here...);
exit(1);
}
read(p[0], 1); // returns when parent exits for any reason
kill(child, 9);
exit(1);
}
使用这种方法有两个小注意事项:
如果你故意杀死中间进程,那么当父进程死亡时,子进程不会被杀死。 如果子进程在父进程之前退出,那么中间进程将尝试杀死原来的子进程pid,该进程现在可以引用一个不同的进程。(这可以通过在中间过程中编写更多代码来解决。)
顺便说一句,我使用的实际代码是Python的。为了完整起见,这里是:
def run(*args):
(r, w) = os.pipe()
child = os.fork()
if child == 0:
os.close(w)
os.setpgid(0, 0)
child = os.fork()
if child == 0:
os.close(r)
os.execl(args[0], *args)
os._exit(1)
os.read(r, 1)
os.kill(child, 9)
os._exit(1)
os.close(r)
其他回答
如果你发送一个信号到pid 0,使用for实例
kill(0, 2); /* SIGINT */
该信号被发送到整个进程组,从而有效地杀死了子进程。
你可以很容易地测试它,比如:
(cat && kill 0) | python
如果你然后按^D,你会看到文本“Terminated”,这表明Python解释器确实已经被杀死,而不是因为stdin被关闭而退出。
我找到了两个解,都不完美。
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'处理程序。退出的地方。 注意: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(.....);
*/
我认为不可能保证只使用标准POSIX调用。就像现实生活一样,一旦孩子被孕育出来,它就有了自己的生命。
父进程可以捕获大多数可能的终止事件,并尝试在此时终止子进程,但总有一些无法捕获。
例如,没有进程可以捕获SIGKILL。当内核处理这个信号时,它将杀死指定的进程,而不通知该进程。
扩展一下类比——唯一的另一种标准方式是,当孩子发现自己不再有父母时自杀。
使用prctl(2)有一种linux独有的方法——请参阅其他答案。
安装一个陷阱处理程序来捕获SIGINT,如果你的子进程还活着,它就会杀死它,尽管其他的帖子是正确的,它不会捕获SIGKILL。
以独占访问的方式打开一个.lockfile,并让子进程尝试打开它——如果打开成功,子进程应该退出
即使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();
}