进程fork()两次---解决一个进程不必等待子进程终止,也不希望子进程处于僵死状态(一般是服务器进程fork())
2015-02-05 11:07
465 查看
首先,要了解什么叫僵尸进程,什么叫孤儿进程,以及服务器进程运行所需要的一些条件。两次fork()就是为了解决这些相关的问题而出现的一种编程方法。
孤儿进程
孤儿进程是指父进程在子进程结束之前死亡(return 或exit)。如下图1所示:
图1 孤儿进程
但是孤儿进程并不会像上面画的那样持续很长时间,当系统发现孤儿进程时,init进程就收养孤儿进程,成为它的父亲,child进程exit后的资源回收就都由init进程来完成。
僵尸进程
僵尸进程是指子进程在父进程之前结束了,但是父进程没有用wait或waitpid回收子进程。如下图所示:
图2 僵尸进程
父进程没有用wait回收子进程并不说明它不会回收子进程。子进程在结束的时候会给其父进程发送一个SIGCHILD信号,父进程默认是忽略SIGCHILD信号的,如果父进程通过signal()函数设置了SIGCHILD的信号处理函数,则在信号处理函数中可以回收子进程的资源。
事实上,即便是父进程没有设置SIGCHILD的信号处理函数,也没有关系,因为在父进程结束之前,子进程可以一直保持僵尸状态,当父进程结束后,init进程就会负责回收僵尸子进程。
但是,如果父进程是一个服务器进程,一直循环着不退出,那子进程就会一直保持着僵尸状态。虽然僵尸进程不会占用任何内存资源,但是过多的僵尸进程总还是会影响系统性能的。黔驴技穷的情况下,该怎么办呢?
这个时候就需要一个英雄来拯救整个世界,它就是两次fork()技法。
两次fork()技法
两次fork()的流程如下所示:
图3 两次fork的控制流
如上图3所示,为了避免子进程child成为僵尸进程,我们可以人为地创建一个子进程child1,再让child1成为工作子进程child2的父进程,child2出生后child1退出,这个时候child2相当于是child1产生的孤儿进程,这个孤儿进程由系统进程init回收。这样,当child2退出的时候,init就会回收child2的资源,child2就不会成为孤魂野鬼祸国殃民了。
<unix环境高级编程>这本书里提供了两次fork的一个例子,代码如下:
[cpp] view
plaincopy
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);
}
理所当然,第二个子进程的父进程是进程号为1的init进程。
一言以蔽之,两次fork()是人为地创建一个工作子进程的父进程,然后让这个人为父进程退出,之后工作子进程就由init回收,避免了工作子进程成为僵尸进程。
孤儿进程
孤儿进程是指父进程在子进程结束之前死亡(return 或exit)。如下图1所示:
图1 孤儿进程
但是孤儿进程并不会像上面画的那样持续很长时间,当系统发现孤儿进程时,init进程就收养孤儿进程,成为它的父亲,child进程exit后的资源回收就都由init进程来完成。
僵尸进程
僵尸进程是指子进程在父进程之前结束了,但是父进程没有用wait或waitpid回收子进程。如下图所示:
图2 僵尸进程
父进程没有用wait回收子进程并不说明它不会回收子进程。子进程在结束的时候会给其父进程发送一个SIGCHILD信号,父进程默认是忽略SIGCHILD信号的,如果父进程通过signal()函数设置了SIGCHILD的信号处理函数,则在信号处理函数中可以回收子进程的资源。
事实上,即便是父进程没有设置SIGCHILD的信号处理函数,也没有关系,因为在父进程结束之前,子进程可以一直保持僵尸状态,当父进程结束后,init进程就会负责回收僵尸子进程。
但是,如果父进程是一个服务器进程,一直循环着不退出,那子进程就会一直保持着僵尸状态。虽然僵尸进程不会占用任何内存资源,但是过多的僵尸进程总还是会影响系统性能的。黔驴技穷的情况下,该怎么办呢?
这个时候就需要一个英雄来拯救整个世界,它就是两次fork()技法。
两次fork()技法
两次fork()的流程如下所示:
图3 两次fork的控制流
如上图3所示,为了避免子进程child成为僵尸进程,我们可以人为地创建一个子进程child1,再让child1成为工作子进程child2的父进程,child2出生后child1退出,这个时候child2相当于是child1产生的孤儿进程,这个孤儿进程由系统进程init回收。这样,当child2退出的时候,init就会回收child2的资源,child2就不会成为孤魂野鬼祸国殃民了。
<unix环境高级编程>这本书里提供了两次fork的一个例子,代码如下:
[cpp] view
plaincopy
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);
}
理所当然,第二个子进程的父进程是进程号为1的init进程。
一言以蔽之,两次fork()是人为地创建一个工作子进程的父进程,然后让这个人为父进程退出,之后工作子进程就由init回收,避免了工作子进程成为僵尸进程。
相关文章推荐
- UNIX环境高级编程有一个例子说fork两次可以避免产生僵死进程,我不知道,为什么fork两次就能避免僵死进程?
- VS2010调试sharepoint2010经常Web服务器进程由IIS终止 的解决办法
- TCP客户端断开连接后,服务器连接处于CLOSE_WAIT状态之解决办法
- 调用 fork() 两次以避免僵死进程
- 服务器进程为何通常fork()两次
- 解决一个 MySQL 服务器进程 CPU 占用 100%解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记》[转]
- 解决新建数据库时的错误 SQL4414N “DB2 管理服务器”处于不活动状态
- 服务器进程为何通常fork()两次
- 服务器进程为何通常fork()两次
- UNIX网络编程卷1 服务器程序设计范式1 并发服务器,为每个客户请求fork一个进程
- 调用 fork() 两次以避免僵死进程
- 调用fork两次以避免僵死进程
- 服务器进程为何通常fork()两次
- 解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记
- VC 6.0 采用菜单 File—>Open 打开 .dsw 工程时,VC 6.0 界面程序处于僵死状态问题解决
- shell同时启多个进程,并等待所有子进程结束,再做接下来的操作,最好能获取每个子进程的退出状态
- 调用 fork() 两次以避免僵死进程
- 服务器进程为何通常fork()两次
- Winform界面中欠套了一个EXCEL模板提示文件处于编辑状态. 解决方法
- Windows监控进程服务器IIS进程状态解决CPU暴满造成服务器运行缓慢 Python版