假设我有一个进程,它只生成一个子进程。现在,当父进程由于某种原因(正常或不正常,通过kill, ^C,断言失败或其他任何原因)退出时,我希望子进程死亡。如何正确地做到这一点?
关于stackoverflow的一些类似问题:
(前面问过)当父进程退出的时候,我怎么能让子进程退出呢? (稍后问)用fork()创建的子进程会在父进程被杀死时自动被杀死吗?
关于Windows的stackoverflow也有类似的问题:
如何在Windows中自动销毁子进程? 当父进程被杀死时,杀死子进程
假设我有一个进程,它只生成一个子进程。现在,当父进程由于某种原因(正常或不正常,通过kill, ^C,断言失败或其他任何原因)退出时,我希望子进程死亡。如何正确地做到这一点?
关于stackoverflow的一些类似问题:
(前面问过)当父进程退出的时候,我怎么能让子进程退出呢? (稍后问)用fork()创建的子进程会在父进程被杀死时自动被杀死吗?
关于Windows的stackoverflow也有类似的问题:
如何在Windows中自动销毁子进程? 当父进程被杀死时,杀死子进程
当前回答
为了完整起见。在macOS上你可以使用kqueue:
void noteProcDeath(
CFFileDescriptorRef fdref,
CFOptionFlags callBackTypes,
void* info)
{
// LOG_DEBUG(@"noteProcDeath... ");
struct kevent kev;
int fd = CFFileDescriptorGetNativeDescriptor(fdref);
kevent(fd, NULL, 0, &kev, 1, NULL);
// take action on death of process here
unsigned int dead_pid = (unsigned int)kev.ident;
CFFileDescriptorInvalidate(fdref);
CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example
int our_pid = getpid();
// when our parent dies we die as well..
LOG_INFO(@"exit! parent process (pid %u) died. no need for us (pid %i) to stick around", dead_pid, our_pid);
exit(EXIT_SUCCESS);
}
void suicide_if_we_become_a_zombie(int parent_pid) {
// int parent_pid = getppid();
// int our_pid = getpid();
// LOG_ERROR(@"suicide_if_we_become_a_zombie(). parent process (pid %u) that we monitor. our pid %i", parent_pid, our_pid);
int fd = kqueue();
struct kevent kev;
EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
kevent(fd, &kev, 1, NULL, 0, NULL);
CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, true, noteProcDeath, NULL);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
CFRelease(source);
}
其他回答
如果父母去世,孤儿的PPID变为1 -你只需要检查你自己的PPID。 在某种程度上,这就是上面提到的轮询。 这是它的外壳部分:
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
子进程是否有连接父进程的管道?如果是这样,那么写入时会收到SIGPIPE,读取时会收到EOF——这些情况都可以检测到。
如果你发送一个信号到pid 0,使用for实例
kill(0, 2); /* SIGINT */
该信号被发送到整个进程组,从而有效地杀死了子进程。
你可以很容易地测试它,比如:
(cat && kill 0) | python
如果你然后按^D,你会看到文本“Terminated”,这表明Python解释器确实已经被杀死,而不是因为stdin被关闭而退出。
即使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();
}
通过在prctl()系统调用中指定PR_SET_PDEATHSIG选项,子进程可以要求内核在父进程死亡时传递SIGHUP(或其他信号),就像这样:
prctl(PR_SET_PDEATHSIG, SIGHUP);
详见man 2 prctl。
编辑:这是linux专用的