创建僵尸进程

25

我有兴趣创建一个僵尸进程。据我了解,当父进程在子进程之前退出时,会出现僵尸进程。但是,我尝试使用以下代码重新创建僵尸进程:

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main ()
{
  pid_t child_pid;

  child_pid = fork ();
  if (child_pid > 0) {
    exit(0);
  }
  else {
    sleep(100);
    exit (0);
  }
  return 0;
}

然而,这段代码在执行后立即退出,这是预期的。但是,我

ps aux | grep a.out

我发现a.out只是像一个普通进程一样运行,而不是像我预期的僵尸进程。

我使用的操作系统是ubuntu 14.04 64位


3
您在问题中的代码不会创建僵尸进程,因为在您的代码中,父进程先退出而子进程继续运行。(请记住,fork() 在子进程中返回0,在父进程中返回子进程的PID。)要查看僵尸进程,您需要使子进程在父进程仍然活着但未等待子进程的情况下退出。如果您只更改代码中第10行的if (child_pid > 0)if (child_pid == 0),它将“修复”您的代码,并且当子进程退出时,您将能够看到一个僵尸进程。 - Susam Pal
2个回答

36

引用:

据我所知,僵尸进程是指当父进程退出后子进程仍在运行时发生的。

这是错误的。根据man 2 wait(请参阅注意事项):

一个已经终止但未被等待的子进程称为“僵尸进程”。

因此,如果您想创建一个僵尸进程,在fork(2)之后,子进程应该exit(),父进程在退出之前应该sleep(),让您有时间观察ps(1)的输出。

例如,您可以使用下面的代码替换您的代码,并在sleep()期间使用ps(1)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void)
{
    pid_t pid;
    int status;

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }

    /* Child */
    if (pid == 0)
        exit(0);

    /* Parent
     * Gives you time to observe the zombie using ps(1) ... */
    sleep(100);

    /* ... and after that, parent wait(2)s its child's
     * exit status, and prints a relevant message. */
    pid = wait(&status);
    if (WIFEXITED(status))
        fprintf(stderr, "\n\t[%d]\tProcess %d exited with status %d.\n",
                (int) getpid(), pid, WEXITSTATUS(status));

    return 0;
}

非常感谢chrk!我尝试了你的代码,发现出现了一些僵尸进程。但我仍然有一个疑问,为什么我的代码没有创建僵尸进程?根据你在帖子中的定义,是因为子进程在父进程没有等待命令的情况下退出了(父进程已经退出了)。@chrk - user3354832
3
在你的问题中,代码并没有创建僵尸进程,因为在你的代码中,父进程先退出而子进程继续运行。(请记住,fork()函数在子进程中返回0,在父进程中返回子进程的PID。) 如果想要看到一个僵尸进程,你需要让子进程在父进程还活着但没有等待子进程的情况下退出。如果你只是将代码中的第10行由 'if (child_pid > 0)' 改为 'if (child_pid == 0)',它将"修复"你的代码,并且当子进程退出时,你将能够看到一个僵尸进程。 - Susam Pal
2
再详细解释一下。如果父进程先退出,那么子进程就成为了孤儿(其父进程已经死亡),init进程将会接管它(所以新的父进程是pid 1)。init进程有一个特殊的处理程序注册,用于在子进程死亡时被通知,因此当子进程死亡时,它将等待子进程读取其状态码,因此子进程不会变成僵尸进程。如果init进程没有这样做(例如在docker内运行时常见),则您的版本仍将具有僵尸进程。 - Moises Silva

5
Linux中的"僵尸进程"指已经完成的进程,但由于父子进程之间缺少对应关系,其条目仍然存在于进程表中。通常,父进程通过wait()函数监视其子进程的状态。当子进程完成时,wait函数会向父进程发出信号,从内存中完全退出进程。但是,如果父进程未能为其任何子进程调用wait函数,则子进程将作为死亡或僵尸进程在系统中继续存在。这些僵尸进程可能会在您的系统上积累大量,并影响其性能。
下面是一个创建僵尸进程的C程序,在我们的系统上运行它即可。将此文件保存为zombie.c:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main ()
{
  pid_t child_pid;

  child_pid = fork ();
  if (child_pid > 0) {
    sleep (60);
  }
  else {
    exit (0);
  }
  return 0;
}

这段代码创建的僵尸进程将运行60秒。您可以通过在sleep()函数中指定时间(以秒为单位)来增加持续时间。

编译此程序。

gcc zombie.c

现在运行僵尸程序:

./a.out

现在,ps命令还将显示这个僵尸进程,请打开一个新的终端并使用以下命令检查僵尸进程:

aamir@aamir:~/process$ ps -ef | grep a.out
aamir    10171  3052  0 17:12 pts/0    00:00:00 ./a.out
aamir    10172 10171  0 17:12 pts/0    00:00:00 [a.out] <defunct> #Zombie process
aamir    10177  3096  0 17:12 pts/2    00:00:00 grep --color=auto a.out

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接