父进程死亡后,如何杀死所有子进程并切换到init?

父进程死亡后,如何杀死所有子进程并切换到init?

我有以下问题:当我的大父进程在创建许多子进程后死亡(意外!)时,所有子进程都切换到init.

我怎样才能安全地杀死所有这些子进程?

我以为有一个办法:通过此命令了解父进程

ps -o ppid= <number of some child process>

完成后我可以使用这个答案并杀死所有子进程。

这里的问题是所有子进程都切换到init并且该解决方案不起作用......

除了 htop 并手动杀死它之外,还有其他方法吗?

先感谢您!

答案1

  1. 短期解决方法:  如果您的大父进程大约在同一时间创建所有子进程,请ps按 STIME(进程启动时间)对输出进行排序。这(连同进程名称)将帮助您识别此调用中的孤儿。
  2. 长期修复:  修改您的大父进程程序以保留其启动的所有进程的 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;
}

相关内容