你如何使用 wait() 杀死僵尸进程

How do you kill zombie process using wait()

我有这段代码需要 parent 来分叉 3 children。

How do you know (and) where to put the "wait()" statement to kill zombie processes?

您可以在父进程的任何地方使用wait(),当子进程终止时,它将从系统中删除。把它放在哪里取决于你,在你的具体情况下,你可能想把它放在 child = fork(); 行之后,这样父进程在它的子进程退出之前不会恢复执行。

What is the command to view zombie processes if you have Linux virtual box?

可以使用ps aux命令查看系统中的所有进程(包括僵尸进程),如果进程是a则STAT列等于Z僵尸。示例输出为:

USER      PID    %CPU %MEM VSZ  RSS TTY      STAT START   TIME COMMAND
daniel    1000   0.0  0.0  0    0   ??       Z    17:15   0:00 command

How do you know (and) where to put the "wait()" statement to kill zombie processes?

如果您的 parent 只生成少量固定数量的 children;不关心他们何时或是否停止、继续或完成; 本身退出很快,那么就不需要使用wait()waitpid()来清理child进程。 init 进程 (pid 1) 负责孤立的 child 进程,并在它们完成后清理它们。

但是,在任何其他情况下,您必须 wait() 用于 child 个进程。这样做可以释放资源,确保 child 已完成,并允许您获得 child 的退出状态。如果您愿意,还可以通过 waitpid() 在信号停止或恢复 child 时收到通知。

至于其中执行等待,

  • 您必须确保 只有 parent wait()s.
  • 您应该在您需要 child 完成的最早时间点或之前等待(但不要在分叉之前),或者
  • 如果你不关心child什么时候完成或者是否完成,但是你需要清理资源,那么你可以定期调用waitpid(-1, NULL, WNOHANG)收集一个僵尸child如果有一个,没有不阻塞

特别是,您必须 而不是 wait()(无条件地)在 fork()ing 之后,因为 parent 和 child 运行同样的代码。你必须用fork()的return值来判断你是在child(return值==0),还是在parent(任意其他 return 值)。此外,仅当分叉成功时 parent 必须 wait(),在这种情况下 fork() return 是 child 的 pid,它始终大于零. return 值小于零表示分叉失败。

您的程序实际上并不需要 wait(),因为它刚好生成四个(而不是三个)children,然后退出。但是,如果你想让 parent 在任何时候最多有一个活的 child,那么你可以这样写:

int main() {
    pid_t child;
    int i;

    printf("-----------------------------------\n");
    about("Parent");

    for (i = 0; i < 3; i++) {
        printf("Now ..  Forking !!\n");
        child = fork();

        if (child < 0) {
            perror ("Unable to fork");
            break;
        } else if (child == 0) {
            printf ("In child #%d\n", (i+1));
            about ("Child");
            break;
        } else {
            /* in parent */
            if (waitpid(child, NULL, 0) < 0) {
                perror("Failed to collect child process");
                break;
            }
        }
    }

    return 0;
}

如果 parent 在它的一个或多个 children 之前退出,如果它不等待就会发生这种情况,那么 child 之后会看到它的 parent 进程是 pid 1.

其他人已经回答了如何通过 ps 命令获取僵尸进程列表。您也可以通过 top 查看僵尸。但是,使用您的原始代码,您不太可能瞥见僵尸,因为 parent 进程退出得非常快,然后 init 将清理它留下的僵尸。

How do you know (and) where to put the "wait()" statement to kill zombie processes?

您可以为 SIGCHLD 注册一个信号处理程序,将全局 volatile sig_atomic_t flag = 0 变量设置为 1。然后,在程序中某个方便的地方,测试 flag 是否设置为 1,然后,如果是这样,将它设置回 0,然后(否则你可能会错过一个信号)在循环中调用 waitpid(-1, NULL, WNOHANG) 直到它告诉你没有更多的进程要等待。请注意,该信号将中断使用 EINTR 的系统调用,这是检查 flag 值的良好条件。如果您使用像 select() 这样的无限期阻塞系统调用,您可能需要指定一个超时时间,之后您将检查 flag,否则您可能会错过在您最后一次 waitpid() 之后发出的信号] 调用,但在进入无限期阻塞系统调用之前。另一种方法是使用 pselect().

使用:

ps -e -opid,ppid,pgid,stat,etime,cmd | grep defunct

查看您的僵尸,还有 ppidpgid 查看 parent ID 和进程组 ID。 etime 查看你的僵尸已经存活的时间(cpu)。 parent ID 可用于向 parent 进程发送自定义信号。

如果 parent 进程被正确编码以捕获和处理 SIGCHLD 信号,并且符合预期(即 wait/reap 僵尸),那么您可以提交:

kill -CHLD <parent_pid>

告诉 parent 收割他们所有的僵尸。