我有以下问题:当我的大父进程在创建许多子进程后死亡(意外!)时,所有子进程都切换到init
.
我怎样才能安全地杀死所有这些子进程?
我以为有一个办法:通过此命令了解父进程
ps -o ppid= <number of some child process>
完成后我可以使用这个答案并杀死所有子进程。
这里的问题是所有子进程都切换到init
并且该解决方案不起作用......
除了 htop 并手动杀死它之外,还有其他方法吗?
先感谢您!
答案1
- 短期解决方法: 如果您的大父进程大约在同一时间创建所有子进程,请
ps
按 STIME(进程启动时间)对输出进行排序。这(连同进程名称)将帮助您识别此调用中的孤儿。 - 长期修复: 修改您的大父进程程序以保留其启动的所有进程的 PID 日志。然后你可以用它作为杀戮列表。
答案2
您可以使用以下方法制定合理的候选名单:
ps -ef | awk '$1 == "myUser" && $3 == 1'
也许还可以通过过滤其他字段来完善这一点,例如 STIME 不用于会话启动,TTY 不用于 ?,以及 CMD 不以 /usr/lib 或 /usr/bin 或 /lib 开头。将列表放入文件中进行最终检查,然后 awk 输出第 2 列 | xargs |杀。
答案3
不可移植,但 Linux 允许不init
重新确定进程的父级,请参阅PR_SET_CHILD_SUBREAPER
参见prctl(2)。
PR_SET_CHILD_SUBREAPER
(自 Linux 3.4 起)
如果精氨酸2非零,设置调用进程的“child subreaper”属性;如果精氨酸2为零,则取消设置该属性。当一个进程被标记为子子收割器时,它创建的所有子进程及其后代都将被标记为具有子收割器。实际上,副收割机的作用是初始化(1)为其后代进程。 ……
然而,你的副收割者也可能会死亡(意外)。另一个选项(同样在 Linux 上)可能是 PID 命名空间或容器。更常见的解决方案是使父进程尽可能简单和健壮,这样它就不太可能被踢出或死亡。
更复杂的是将子进程链接到父进程,尽管如果子进程执行其他操作,或者如果子进程不能使用异步 I/O 来复杂化,则这可能是不可能的,因为子进程必须检查管道EOF 注意到父进程已经离开:
#include <err.h>
#include <errno.h>
#include <unistd.h>
int main(void)
{
int fd[2];
char ch;
ssize_t ret;
pipe(fd);
switch (fork()) {
case -1:
err(1, "fork failed");
case 0:
close(fd[1]);
warnx("child %d start", getpid());
/* this would really need to be done in an event loop so the
* child can do other things meanwhile */
ret = read(fd[0], &ch, 1);
if (ret == 0)
errx(1, "EOF from parent (child %d)", getpid());
break;
default:
/* and another child process... */
switch (fork()) {
case -1:
err(1, "fork failed");
case 0:
close(fd[1]);
warnx("child %d start", getpid());
ret = read(fd[0], &ch, 1);
if (ret == 0)
errx(1, "EOF from parent (child %d)", getpid());
break;
default:
sleep(9);
}
}
return 0;
}