相关主题
1:listener为何要fork两次子进程
2:为何listener要fork两次子进程,这里面有我的观点,本文主要是把以前模拟日记分享出来
模拟进程说明
c代码非常简单,主要就是fork,execv,wait,exit及输出一些标识,有简单的c知识都能看懂
listener.c:模拟oracle listener
serverprocess.c:模拟oracle serverprocess
listener.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
pid_t fpid,cpr;
int count=0;
char *argnew[]={"serverprocessd",NULL};
fpid=fork();
if (fpid < 0)
printf("###Parent fork error!\n");
else if (fpid == 0) {
printf(" Child, pid=%d\n",getpid());
sleep(5);
printf(" Child sleeped5S,will fork serverprocess\n");
cpr=fork();
printf(" Child fork end!\n");
if (cpr<0)
printf("######Child fork error!\n");
else if (cpr==0){
while (1){
printf(" Grandchild has been born,will change to serverprocess after 5S,pid=%d\n",getpid());
sleep(5);
if (execv("/home/test/serverprocessd",argnew)<0){
printf("###########Grandchild execv error!");
}
printf(" Grandchild changing successfully!,pid=%d\n",getpid());
count++;
if (count>14){
printf(" Grandchild serverprocess will exit after 5S\n");
sleep(5);
printf("------------Grandchild serverprocess exit,pid=%d\n",getpid());
exit(0);
}
}
}else{
printf(" Child will sleep 5S,then exit\n");
sleep(5);
printf("------Child exit,pid=%d\n",getpid());
exit(0);
}
}else{
printf(" Parent,pid=%d\n",getpid());
while (1)
{
sleep(15);
printf(" Parent Sleeped15S,begin wait\n");
wait(NULL);
count++;
printf(" Parent wait end,count=%d\n",count);
if (count>3){
printf("---Parent will exit,pid=%d\n",getpid());
exit(0);
}
}
}
return 0;
}
serverprocess.c
#include<stdio.h>
int main(void)
{
while (1){
sleep(3);
printf("___^_^ I'am serverprocess,have worked 3S\n");
}
return 0;
}
进程运行及输出
root@IPS3DEV test]# ./listenerd
Parent,pid=14836
Child, pid=14837
Child sleeped5S,will fork serverprocess
Child fork end!
Child will sleep 5S,then exit
Child fork end!
Grandchild has been born,will change to serverprocess after 5S,pid=14840
------Child exit,pid=14837
___^_^ I’am serverprocess,have worked 3S
Parent Sleeped15S,begin wait
Parent wait end,count=1
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
Parent Sleeped15S,begin wait
Parent wait end,count=2
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
Parent Sleeped15S,begin wait
Parent wait end,count=3
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
Parent Sleeped15S,begin wait
Parent wait end,count=4
—Parent will exit,pid=14836
[root@IPS3DEV test]# ___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
___^_^ I’am serverprocess,have worked 3S
进程监控及说明
[root@IPS3DEV ~]# ps -ax|grep -e listenerd -e serverprocessd
14836 pts/0 S+ 0:00 ./listenerd #pid=14836,主进程,监听进程
14837 pts/0 S+ 0:00 ./listenerd #pid=14837,子进程1,由监听fork
[root@IPS3DEV ~]# ps -ax|grep -e listenerd -e serverprocessd
14836 pts/0 S+ 0:00 ./listenerd #pid=14836,主进程,监听进程
14837 pts/0 S+ 0:00 ./listenerd #pid=14837,子进程1,由监听fork
14840 pts/0 S+ 0:00 ./listenerd #pid=14840,子进程2,由子进程1 fork
[root@IPS3DEV ~]# ps -ax|grep -e listenerd -e serverprocessd
14836 pts/0 S+ 0:00 ./listenerd
14837 pts/0 Z+ 0:00 [listenerd] <defunct> #pid=14837,子进程1退出变成僵尸进程
14840 pts/0 S+ 0:00 serverprocessd #pid=14840,子进程2,由子进程1 fork,借尸还魂,调用exec变成serverprocess进程,注意pid号没变
[root@IPS3DEV ~]# ps -ax|grep -e listenerd -e serverprocessd
14836 pts/0 S+ 0:00 ./listenerd #pid=14836,主进程,监听进程,调用wait释放了子进程1的资源,子进程1消失了
14840 pts/0 S+ 0:00 serverprocessd
…
[root@IPS3DEV ~]# ps -ax|grep -e listenerd -e serverprocessd
14836 pts/0 S+ 0:00 ./listenerd
14840 pts/0 S+ 0:00 serverprocessd
[root@IPS3DEV ~]# ps -ax|grep -e listenerd -e serverprocessd
14840 pts/0 S 0:00 serverprocessd
同时间其它监控
[root@IPS3DEV ~]#
[root@IPS3DEV ~]# ps -ef|grep -e listenerd -e serverprocessd
root 14836 4936 0 10:55 pts/0 00:00:00 ./listenerd #4936的信息:root 4936 4934 0 09:04 pts/0 00:00:00 -bash
root 14837 14836 0 10:55 pts/0 00:00:00 ./listenerd #pid=14837,子进程1,由监听fork
root 14840 14837 0 10:55 pts/0 00:00:00 ./listenerd #pid=14840,子进程2,由子进程1 fork,注意父进程号14837
[root@IPS3DEV ~]# ps -ef|grep -e listenerd -e serverprocessd
root 14836 4936 0 10:55 pts/0 00:00:00 ./listenerd
root 14837 14836 0 10:55 pts/0 00:00:00 [listenerd] <defunct> #pid=14837,子进程1退出变成僵尸进程
root 14840 1 0 10:55 pts/0 00:00:00 serverprocessd #pid=14840,子进程2,由子进程1 fork,注意它的父进程由14837变成了1;1号进程就是/sbin/init
[root@IPS3DEV ~]# ps -ef|grep -e listenerd -e serverprocessd
root 14836 4936 0 10:55 pts/0 00:00:00 ./listenerd #pid=14836,主进程,监听进程,调用wait释放了子进程1的资源,子进程1消失了
root 14840 1 0 10:55 pts/0 00:00:00 serverprocessd
…
[root@IPS3DEV ~]# ps -ef|grep -e listenerd -e serverprocessd
root 14836 4936 0 10:55 pts/0 00:00:00 ./listenerd
root 14840 1 0 10:55 pts/0 00:00:00 serverprocessd
[root@IPS3DEV ~]# ps -ef|grep -e listenerd -e serverprocessd
root 14840 1 0 10:55 pts/0 00:00:00 serverprocessd
总结
为什么listener要fork两次?如下,假设:
1.listener只fork一个进程,这个进程调exec成为serverprocess
2.listener fork一个子进程1,子进程1再fork一个子进程2,子进程2调用exec成为serverprocess
1的局限性:listener进程fork子进程后如果不调wait,子进程终止后将成为僵尸进程,浪费系统资源;如果listener调用wait势必被阻塞,在子进程退出前,无法响应其它连接请求
2的优势:listener fork子进程1,子进程1 fork子进程2后立马退出,这时候子进程1变成僵尸进程,等listener调用Wait后正常退出,由于子进程1已经退出变僵尸进程listener进程调用Wait处理不会被阻塞,可以立即响应其它连接请求,子进程1退出变僵尸后,子进程2的父进程变成1,也可以自行终止被init回收不会变为僵尸进程浪费系统资源。