首先,要了解什么叫僵尸进程,什么叫孤儿进程,以及服务器进程运行所需要的一些条件。两次fork()就是为了解决这些相关的问题而出现的一种编程方法。

孤儿进程

孤儿进程是指父进程在子进程结束之前死亡(return 或exit)。如下图所示:

但是孤儿进程并不会像上面画的那样持续很长时间,当系统发现孤儿进程时,init进程就收养孤儿进程,成为它的父亲,child进程exit后的资源回收就都由init进程来完成。

僵尸进程

僵尸进程是指子进程在父进程之前结束了,但是父进程没有用wait或waitpid回收子进程。如下图所示:

父进程没有用wait回收子进程并不说明它不会回收子进程。子进程在结束的时候会给其父进程发送一个SIGCHILD信号,父进程默认是忽略SIGCHILD信号的,如果父进程通过signal()函数设置了SIGCHILD的信号处理函数,则在信号处理函数中可以回收子进程的资源。

事实上,即便是父进程没有设置SIGCHILD的信号处理函数,也没有关系,因为在父进程结束之前,子进程可以一直保持僵尸状态,当父进程结束后,init进程就会负责回收僵尸子进程。

但是,如果父进程是一个服务器进程,一直循环着不退出,那子进程就会一直保持着僵尸状态。虽然僵尸进程不会占用任何内存资源,但是过多的僵尸进程总还是会影响系统性能的。黔驴技穷的情况下,该怎么办呢?

这个时候就需要一个英雄来拯救整个世界,它就是两次fork()技法。

两次fork()技法

两次fork()的流程如下所示:

《UNIX环境高级编程》(下载见http://www.linuxidc.net/thread-2063-1-1.html)这本书里提供了两次fork的一个例子,代码如下:

  1. int main(void)
  2. {
  3. pid_t        pid;
  4. if ( (pid = fork()) < 0)
  5. err_sys("fork error");
  6. else if (pid == 0)
  7. {                /* first child */
  8. if ( (pid = fork()) < 0)
  9. err_sys("fork error");
  10. else if (pid > 0)
  11. exit(0);        /* parent from second fork == first child */
  12. /* We're the second child; our parent becomes init as soon
  13. as our real parent calls exit() in the statement above.
  14. Here's where we'd continue executing, knowing that when
  15. we're done, init will reap our status. */
  16. sleep(2);
  17. printf("second child, parent pid = %d\n", getppid());
  18. exit(0);
  19. }
  20. if (waitpid(pid, NULL, 0) != pid)        /* wait for first child */
  21. err_sys("waitpid error");
  22. /* We're the parent (the original process); we continue executing,
  23. knowing that we're not the parent of the second child. */
  24. exit(0);
  25. }

理所当然,第二个子进程的父进程是进程号为1的init进程。

一言以蔽之,两次fork()是为了防止系统中产生僵尸进程。

服务器进程为何通常fork()两次的更多相关文章

  1. 为何要fork()两次来避免产生僵尸进程?

    为何要fork()两次来避免产生僵尸进程?   当我们只fork()一次后,存在父进程和子进程.这时有两种方法来避免产生僵尸进程: 父进程调用waitpid()等函数来接收子进程退出状态. 父进程先结 ...

  2. daemon进程fork一次和fork两次的区别?

    守护进程也称为精灵进程(Daemon),是运行在后台的一种特殊的进程.它独立于控制终端并且周期性的执行某种任务负等待处理某些发生的事件.因为他们没有控制终端,所以说他们是在后台运行的. 守护进程的特点 ...

  3. 进程控制之fork函数

    一个现有进程可以调用fork函数创建一个新进程. #include <unistd.h> pid_t fork( void ); 返回值:子进程中返回0,父进程中返回子进程ID,出错返回- ...

  4. 进程创建函数fork()、vfork() ,以及excel()函数

    一.进程的创建步骤以及创建函数的介绍 1.使用fork()或者vfork()函数创建新的进程 2.条用exec函数族修改创建的进程.使用fork()创建出来的进程是当前进程的完全复制,然而我们创建进程 ...

  5. UNIX环境编程学习笔记(19)——进程管理之fork 函数的深入学习

    lienhua342014-10-07 在“进程控制三部曲”中,我们学习到了 fork 是三部曲的第一部,用于创建一个新进程.但是关于 fork 的更深入的一些的东西我们还没有涉及到,例如,fork ...

  6. linux进程原语之fork()

    一.用法解析: fork()这个函数,可以说是名如其人了,众所周知fork这个单词本意为叉子,老外取学术名字的时候总会有一些象形的想法,于是就有了下图~ fork()函数是计算机程序设计中的分叉函数. ...

  7. 【Linux编程】进程标识符与fork函数

    ID为0的进程一般是调度进程.常被称为交换进程(swapper),是内核中的系统进程. ID为1的进程叫做init进程,是一个普通用户进程,不属于内核,由内核调用. 一个现有进程能够调用fork函数创 ...

  8. ORACLE内存结构:PGA And UGA,ORACLE用户进程、服务器进程

    执行一个SQL语句 执行查询语句的过程: 用户进程执行一个查询语句如select * from emp where empno=7839 用户进程和服务器进程建立连接,把改用户进程的信息存储到PGA的 ...

  9. [Chapter 3 Process]Practice 3.1 相关知识:进程创建、fork函数

    3.1 Using the program shown in the Figure3.30, explain what the output will be at LINE A 答案:LINE A 处 ...

随机推荐

  1. django 外键 ,django __

    data sqlite> select * from author; id name age 1 jim 12 2 tom 11 sqlite> select * from book; i ...

  2. RSA (cryptosystem)

    https://en.wikipedia.org/wiki/RSA_(cryptosystem) RSA is one of the first practical实用性的 public-key cr ...

  3. 浅谈Websocket、Ajax轮询和长连接(long pull)

    最近看到了一些介绍Websocket的文章,觉得挺有用,所以在这里将自己的对其三者的理解记录一下. 1.什么是Websocket Websocket是HTML5中提出的新的协议,注意,这里是协议,可以 ...

  4. SQL注入与Java

    前面这篇文章介绍了SQL注入,并且主要就PHP的内容做了实验: http://www.cnblogs.com/charlesblc/p/5987951.html 还有这篇文章对处理方案做了介绍(Pre ...

  5. HDU 1024 (不重叠m段最大和) Max Sum Plus Plus

    题解是看的这里的: http://www.acmerblog.com/hdu-1024-Max-Sum-Plus-Plus-1276.html 当前这个状态是dp[i][j],i 表示当前的段,j表示 ...

  6. hdu 4619 Warm up 2 网络流 最小割

    题意:告诉你一些骨牌,然后骨牌的位置与横竖,这样求最多保留多少无覆盖的方格. 这样的话有人用二分匹配,因为两个必定去掉一个,我用的是最小割,因为保证横着和竖着不连通即可. #include <s ...

  7. js,正则应用

    //获取URL中的request参数 function getUrlParam(name) { var reg = new RegExp("(^|&)" + name + ...

  8. [转] 判断html页是否滚动停止

    原文链接:http://www.phpernote.com/javascript-function/754.html 最近有个项目中遇到这样一个问题: 有一个用于展示数据的带滚动条的DIV块,业务需求 ...

  9. cookie随便写的一点笔记(抄书的)

    cookie是保存在客户端的文本,能够在一定程度上提高用户体验.Servlet API 中提供了Cookie类,可以创建Cookie对象,并通过响应中的addCookie方法,将cookie保存到客户 ...

  10. 添加第三方类库造成的linker command failed with exit code 1 (use -v to see invocation)的错误调试

    linker command failed with exit code 1 (use -v to see invocation)这个错误貌似遇见并不止一次,当我想用某个第三方类库的时候(如SBJso ...