Linux进程--僵尸进程

僵尸进程和如何防止其产生。

Zombie state : When a process is created in UNIX using fork() system call, the address space of the Parent process is replicated. If the parent process calls wait() system call, then the execution of parent is suspended until the child is terminated. At the termination of the child, a ‘SIGCHLD’ signal is generated which is delivered to the parent by the kernel. Parent, on receipt of ‘SIGCHLD’ reaps the status of the child from the process table. Even though, the child is terminated, there is an entry in the process table corresponding to the child where the status is stored. When parent collects the status, this entry is deleted. Thus, all the traces of the child process are removed from the system. If the parent decides not to wait for the child’s termination and it executes its subsequent task, then at the termination of the child, the exit status is not read. Hence, there remains an entry in the process table even after the termination of the child. This state of the child process is known as the Zombie state.

上文的大意是:当子进程结束后,仍然会在系统的进程表中有一个表项存储着子进程的退出状态信息,如果父进程不执行wait获取子进程的退出状态,那么进程表中的子进程表项就会一直存在下去,我们把子进程结束了,资源释放了,但是在进程表中依然有一个表项的状态称为僵尸状态。这里的进程表项其实就是task_struct结构体.

// A C program to demonstrate working of

// fork() and process table entries.

#include

#include

#include

#include

int main()

{

    int i;

    int pid = fork();

  
    if (pid == 0)

    {

        for (i=0; i<20; i++)

            printf("I am Child\n");

    }

    else

    {

        printf("I am Parent\n");

        while(1);

    }

}

 

Linux进程--僵尸进程_第1张图片

在终端执行ps -aux查看进程表:

 

Linux进程--僵尸进程_第2张图片

这里的[a.out] 就是僵尸进程。

为什么要防止僵尸进程的产生呢?

There is one process table per system. The size of the process table is finite. If too many zombie processes are generated, then the process table will be full. That is, the system will not be able to generate any new process, then the system will come to a standstill. Hence, we need to prevent the creation of zombie processes.

大意是:一个系统只有一个进程表,进程表的大小是有限的。如果有太多的僵尸进程产生,那么进程表将会变满,导致系统不能再产生新的进程,然后系统就会进入一个僵死状态,因此我们需要防止僵尸进程的产生。

下面介绍三种防止僵尸进程产生的方法。

方法1:用系统调用wait()

Using wait() system call : When the parent process calls wait(), after the creation of a child, it indicates that, it will wait for the child to complete and it will reap the exit status of the child. The parent process is suspended(waits in a waiting queue) until the child is terminated. It must be understood that during this period, the parent process does nothing just waits.

父进程调用wait()等待子进程结束和获取它的状态,父进程在子进程结束前是挂起的,父进程干不了其他事。显然这种方法并不可取。

// A C program to demonstrate working of

// fork()/wait() and Zombie processes

#include

#include

#include

#include

int main()

{

    int i;

    int pid = fork();

    if (pid==0)

    {

        for (i=0; i<20; i++)

            printf("I am Child\n");

    }

    else

    {

        wait(NULL);

        printf("I am Parent\n");

        while(1);

    }

}

方法2:忽略SIGCHLD信号

By ignoring the SIGCHLD signal : When a child is terminated, a corresponding SIGCHLD signal is delivered to the parent, if we call the ‘signal(SIGCHLD,SIG_IGN)’, then the SIGCHLD signal is ignored by the system, and the child process entry is deleted from the process table. Thus, no zombie is created. However, in this case, the parent cannot know about the exit status of the child.

父进程调用signal(SIGCHLD,SIG_IGN),会导致子进程结束后收不到SIGCHLD信号,但是子进程的进程表项是可以从进程表中删除的,因此不会产生僵尸进程,但是,这样一来,父进程就无法获取子进程退出的状态了。这种方法也有缺点。

// A C program to demonstrate ignoring 

// SIGCHLD signal to prevent Zombie processes

#include

#include

#include

#include

int main()

{

    int i;

    int pid = fork();

    if (pid == 0){

        for (i=0; i<20; i++)

            printf("I am Child\n");

    }else
    {

        signal(SIGCHLD,SIG_IGN);

        printf("I am Parent\n");

        while(1);

    }

}

方法3:用信号处理函数

By using a signal handler : The parent process installs a signal handler for the SIGCHLD signal. The signal handler calls wait() system call within it. In this senario, when the child terminated, the SIGCHLD is delivered to the parent. On receipt of SIGCHLD, the corresponding handler is activated, which in turn calls the wait() system call. Hence, the parent collects the exit status almost immediately and the child entry in the process table is cleared. Thus no zombie is created.

父进程安装SIGCHLD信号函数,在信号函数中调用wait()。当子进程结束,父进程收到SIGCHLD信号后,信号处理函数被激活,然后wait()被调用。因此父进程可以立即获取子进程退出状态,并且子进程的进程表项被删除,不会产生僵尸进程。

// A C program to demonstrate handling of

// SIGCHLD signal to prevent Zombie processes.

#include

#include

#include

#include

  
void func(int signum)

{
    wait(NULL);

}

int main()

{

    int i;

    int pid = fork();

    if (pid == 0)

        for (i=0; i<20; i++)

            printf("I am Child\n");

    else
    {

        signal(SIGCHLD, func);

        printf("I am Parent\n");

        while(1);

    }

}

 

你可能感兴趣的:(Linux进程调度,僵尸进程)