fork()函数的执行过程、孤儿进程和僵尸进程

说起fork就不得不提COW(Copy On Write),就是“写时拷贝”。也就是当fork发生时,子进程根本不会去拷贝父进程的内存页面,而是与父进程共享。当子进程或父进程需要修改一个内存页面时,Linux就将这个内存页面复制一份给修改者,然后再去修改,这样从用户的角度看,父子进程根本就没有共享什么内存。COW也就是进程要写共享的内存页面,先复制再改写。

采用了COW技术后,fork时,子进程还需要拷贝父进程的页面表。这种拷贝的代价就非常小了,对于CPU来说用不了几个时钟周期。

1.孤儿进程

孤儿进程:就是没有父进程的进程。一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

2.僵尸进程

僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。

3.危害

僵尸进程会占用系统资源,如果很多,则会严重影响服务器的性能
孤儿进程不会占用系统资源,最终是由init进程托管,由init进程来释放它。
处理流程:
只要老爹不等wait(sys/wait.h)儿子,儿子都将成为孤魂野鬼zombie(zombie),unix中默认老爹总是想看儿子死后的状态(以便报仇)  
  if   老爹比儿子先再见  
  儿子将被init(id   =   1)收养,最后的结果是zombie儿子彻底再见,系统资源释放  
  else    
      {  
        儿子的zombie将一直存在,系统资源占用...  
        if   老爹dead    
            儿子将被init(id   =   1)收养,最后的结果是zombie儿子彻底再见,系统资源释放  
   
      else   类似的儿子zombie越来越多,系统就等死了!!!  
    }

signal(SIGCHLD, SIG_IGN); //忽略SIGCHLD信号,这常用于并发服务器的性能的一个技巧
                          //因为并发服务器常常fork很多子进程,子进程终结之后需要
                          //服务器进程去wait清理资源。如果将此信号的处理方式设为
                          //忽略,可让内核把僵尸子进程转交给init进程去处理,省去了
                          //大量僵尸进程占用系统资源。(Linux Only)

4.如何防止僵尸进程

首先明白如何产生僵尸进程:
1、子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它
2、父进程没有调用wait()或waitpid()函数来等待子进程的结束
第一种方法:  捕捉SIGCHLD信号,并在信号处理函数里面调用wait函数
转贴Richard Steven的Unix Network Programming代码

int
main(int argc, char **argv)
{
                ...
        Signal(SIGCHLD, sig_chld);
                for(;
                }
                ...
}

void
sig_chld(int signo)
{
        pid_t        pid;
        int        stat;

while ( (pid = waitpid(-1, &stat, WNOHANG)) >; 0)
                printf("child %d terminated/n", pid);
        return;
}

第二种方法:两次fork():转载
在《Unix 环境高级编程》里关于这个在8.6节有非常清楚的说明。

实例
回忆一下8 . 5节中有关僵死进程的讨论。如果一个进程要fork一个子进程,但不要求它等待
子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍是调用f o r k
两次。程序8 - 5实现了这一点。
在第二个子进程中调用s l e e p以保证在打印父进程I D时第一个子进程已终止。在f o r k之后,
父、子进程都可继续执行——我们无法预知哪一个会先执行。如果不使第二个子进程睡眠,则
在f o r k之后,它可能比其父进程先执行,于是它打印的父进程I D将是创建它的父进程,而不是
i n i t进程(进程ID 1)。

#include        <sys/types.h>
#include        <sys/wait.h>
#include        "ourhdr.h"

int main(void)
{
        pid_t        pid;

if ( (pid = fork()) < 0)
                err_sys("fork error");
        else if (pid == 0) {                /* first child */
                if ( (pid = fork()) < 0)
                        err_sys("fork error");
                else if (pid > 0)
                        exit(0);        /* parent from second fork == first child */

/* We‘re the second child; our parent becomes init as soon
                   as our real parent calls exit() in the statement above.
                   Here‘s where we‘d continue executing, knowing that when
                   we‘re done, init will reap our status. */

sleep(2);
                printf("second child, parent pid = %d/n", getppid());
                exit(0);
        }

if (waitpid(pid, NULL, 0) != pid)        /* wait for first child */
                err_sys("waitpid error");

/* We‘re the parent (the original process); we continue executing,
           knowing that we‘re not the parent of the second child. */

exit(0);
}

时间: 2024-11-05 19:28:33

fork()函数的执行过程、孤儿进程和僵尸进程的相关文章

wait函数返回值总结,孤儿进程与僵尸进程[总结]

http://blog.csdn.net/astrotycoon/article/details/41172389 wait函数返回值总结 http://www.cnblogs.com/Anker/p/3271773.html 孤儿进程与僵尸进程[总结]

函数的执行过程——按值传递

上一篇博客我大概介绍了函数的由来和函数的执行过程,接下来,我要说明一下函数在执行的时候参数的传递方式--按值传递. 首先先用C++给大家写个函数,这个函数的功能是比较两个数的大小.然后函数参数在栈中的传递过程我会给大家贴张图. <span style="font-family:KaiTi_GB2312;font-size:18px;">#include<iostream> using namespace std; int max(int x ,int y) {

【Linux】孤儿进程和僵尸进程

本文转载自:http://www.cnblogs.com/anker/p/3271773.html 并做了小幅修改. 1.基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些

python学习笔记——孤儿进程和僵尸进程

1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调用wait()或waitpid()语句来等待子进程结束再退出. 孤儿进程:父进程结束后还有基于该父进程创建的子进程(一个或多个)尚没有结束,此时的子进程称之为孤儿进程:孤儿进程将被init进程(进程树中除了init都有父进程)接受,也就意味着init进程负责孤儿进程完成状态收集工作.一般而言,ini

进程控制、孤儿进程和僵尸进程

一.进程控制 1.进程标识 1.操作系统里每打开一个进程都会创建一个进程ID,这是唯一标识进程的编号,即PID. 2.PID 在任何时刻都是唯一的,但是可以重用.当进程终止并被回收以后,其 PID 就会被系统回收 3.进程的 PID 由系统内核根据延迟重用算法生成,以确保新进程的 PID 不同于最近终止进程的 PID. 4.进程PID的最大值是有限的(因系统的不同而不同),需要及时回收 2.特殊进程 0 号进程:通常是调度进程,常常被称为交换进程(swapper).该进程是内核的一部分,所有进程

孤儿进程和僵尸进程

孤儿进程和僵尸进程 一.定义:什么是孤儿进程和僵尸进程 僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出.这个子进程就是僵尸进程. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程将会导致资源浪费,而孤儿则不会. 子进程持续10秒钟的僵尸状态(EXIT_ZOMBIE)------------------------------

孤儿进程与僵尸进程[总结]

http://www.cnblogs.com/Anker/p/3271773.htm 1.前言 之前在看<unix环境高级编程>第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊.今天被人问到什么是孤儿进程和僵尸进程,会带来什么问题,怎么解决,我只停留在概念上面,没有深入,倍感惭愧.晚上回来google了一下,再次参考APUE,认真总结一下,加深理解. 2.基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程

孤儿进程与僵尸进程【比较】

今天在群里聊起僵尸进程,才发现自己把僵尸进程和孤儿进程搞混了,简直不能原谅.速度查了一下,原来如此.感谢原作者的分享,如下:    1.基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在

孤儿进程与僵尸进程[总结](转载)

1.前言 之前在看<unix环境高级编程>第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊.今天被人问到什么是孤儿进程和僵尸进 程,会带来什么问题,怎么解决,我只停留在概念上面,没有深入,倍感惭愧.晚上回来google了一下,再次参考APUE,认真总结一下,加深理解. 2.基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完

020_Linux的孤儿进程与僵尸进程(Unix系统编程)

1.前言 之前在看<unix环境高级编程>第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊.今天被人问到什么是孤儿进程和僵尸进程,会带来什么问题,怎么解决,我只停留在概念上面,没有深入,倍感惭愧.晚上回来google了一下,再次参考APUE,认真总结一下,加深理解. 2.基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完成