Linux fork函数详细图解-同时分析一道腾讯笔试题

原创blog,转载请注明出处

头文件:

#include<unistd.h>
#include<sys/types.h>
函数原型:
pid_t fork( void);
(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中)
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
注意,子进程是父进程的副本,拷贝父进程的数据空间,堆栈等资源。父子进程不共享上述资源。
每执行一次fork()函数,会返回两次,一次是在父进程,一次是在子进程,两次的返回值不一样。

我们来看一个简单的例子

#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char ** argv )
{
  pid_t result = fork();
  if(result < 0)
  {
        printf("Error");
  }
  else if(result == 0)
  {
        printf("From the son");
  }
  else
  {
        printf("From the father");
  }
}

输出

From the son
From the father

可以看到,父子进程都同时执行了这段代码。可以这么理解,子进程拷贝父进程的所有代码,和堆栈,然后从fork()的下一行,子进程执行

再看一个例子

代码

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char ** argv )
{
         int i;
         for(i = 0;i < 2;i++)
         {
               fork();
               printf("%d\n",i);
         }
}


然后我们编译执行
执行的结果是
[root@localhost test]# gcc -o first first.c 
[root@localhost test]# ./first 
0
1
1
0
1
1


为了便于分析,我们每次都输出当前进程的ppid(父进程)以及当前进程的pid

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char ** argv )
{
         int i;
         for(i = 0;i < 2;i++)
         {
               fork();
               printf("%d PPID:%d PID:%d\n",i,getppid(),getpid());
         }
}

结果

[root@localhost test]# ./first
0 PPID:4984 PID:4985
1 PPID:4985 PID:4986
1 PPID:4984 PID:4985
0 PPID:4424 PID:4984
1 PPID:4984 PID:4987
1 PPID:4424 PID:4984
先分析PID,一共有4种,所以一共有4984,4985,4986,4987四个进程,所以4424是最开始的进程(main)的父进程,所以,最开始的进程是4984
然后依据pid来梳理进程的父子关系
按照子进程->父进程
4986->4985->4984->4424
4987->4984->4424

所以按照这个关系,我们画图来分析比较直观

其中,输出的顺序按照红色圈中顺序来输出

由图可以看出,在我的这个CentOS系统中,子进程比父进程先执行,执行顺序在不同系统中不一样,所以编程的时候应当不依赖执行某一个系统的顺序

然后,我们来分析一道经典的笔试面试题

     for(i = 0;i < 2;i++)
         {
               fork();
               printf("%d\n",i);
         }
}

  for(i = 0;i < 2;i++)
         {
               fork();
               printf("%d",i);
         }
}

各输出了几个0,几个1

对于前者

输出是

0
1
1
0
1
1

对于后者

输出是

01010101
对于前者,在上面已经进行了图解,所以不难理解,对于后者,不少同学会很奇怪,为什么输出了4个0,4个1?

原因是:C语言中,printf函数如果遇到\n,会立即输出缓冲区内所有内容,如果没有\n,会先输出到缓冲区内,等待输出

我们继续画图来分析,



这里在详细解释下:可以这么理解,每次printf的时候,是把本进程的printf缓冲区,加入到总的printf缓冲区(这种说法可能不严谨),比如到红色圈圈3的时候,4985本身在红色圈圈1的时候缓冲区已经有0了,那么再加入1,则本身进程的缓冲区为01,那么加入到printf总的缓冲区就是0101

原创blog,转载请注明出处



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。