fork()函数


问题导入:大家应该都对进程有一个概念,我们从硬盘上找到我们写下的.c文件代码,在linux中我们通过输入驱动命令让预处理器、编译器、汇编器和连接器给我们最后生成一个可
执行的目标文件,然后再给一个执行命令,将这个可执行的文件加载进内存执行。就在可执行文件加载进内存的时候,生成一个新的进程,供cpu管理和控制它的执行。那这里就有一个疑问了,
这里cpu是自动为我们生成了一个进程,它是怎样生成的呢?我们自己能不能手动创建一个新的进程呢?
       
答案是肯定的,系统使用的是fork函数创建进程,fork是一个系统调用,如果我们想在自己的程序中手动的创建新进程,我们也可以使用这个函数。
首先,这个函数的声明是:pid_t fork(void);
使用fork()函数需要包含的头函数,pid_t是在头文件里定义的,所以这个文件也要包括。
函数的参数为空,不需要传入参数,但是这个函数的返回值很重要。调用fork()的函数我们称为父进程,而因为fork()而生成的另外一个进程称为子进程。父进程返回值为新进程的pid,而新进程返回值为0。为什么一个函数调用可以返回两个值呢?
这是因为fork()一旦调用会产生两个一模一样的进程,所以在父进程中有一份自己的代码,而子进程中也复制了一份和父进程一样的代码,所以相当于在两个进程中执行一个代码,那两个进程中每个进程都有自己的一个返回值,且仅返回了一个,这样的角度看,还是符合c语言的语法,函数只有能返回一个值。
还有一个小地方需要强调一下,在子进程赋值父进程的内容时,程序计数器也会复制过去(也就是指向下一条待执行的指令)。为什么这样呢?
 因为如果我们的子进程又从main()的第一条指令执行,那么又会需要执行fork()这条指令(子进程内容和父进程完全一样),那子进程又会生成新进程,如此下去,岂不是死循环了!
        那原理说的得差不多了,我们写一个简单的代码使用和测试一下吧。
fork()函数

运行结果:

fork()函数


这个代码和运行结果是不是证实了我上面所说的。因为一个程序运行if else语句只能进入一个,现在两个值却都能输出,正是因为我们产生了两个进程,getpid()意思是得到当前进程的pid号
还有一个需要注意的是大家是不是发现我们打印完父进程的信息,也就是父进程结束之后,命令提示行就出来了,还没等子进程运行和输出完成。
这是因为我们的终端只能检测到当前运行的进程,对于fork()出来的子进程,它是察觉不到的,所以只要父进程一执行完成,它就认为进程已经执行完成,所以直接输出命令提示行。
        下面我们了解了fork()基本原理,我们就可以思考一些题目更加深入了解一下fork();
       
        题目1:int main()
              {
pid_t n;
               for(int i=0;i<2;i )
               {
                 if(fork())
                 {
                    printf("A\n");
                  }
else
                {
                   printf("B\n");
                 }
               }
     
              如果执行上面代码会输出什么?
              我们看图分析
fork()函数
首先进入第一次循环i=0,这个时候fork()出了一个子进程,那这个父进程的返回值当然是非0,所以输出A(黑色字体),而生成的子进程则返回值为0输出B(第一行第二个框黑色字体),那复制过去所有内容一样,两个独立的进程的i为0的时候执行完了,都要执行i为1时了。这个时候原来的父进程在fork一次,它的返回值还是非0,所以输出A(蓝色),而新的子进程输出B(红色)。而原来的子进程,因为也在调用了fork(),所以它现在相对来说是父进程了输出A(蓝色),生成的子进程输出B(红色字体)。所以我们就会得到3个A和3个B的输出,但是因为fork()之后的两个进程是独立的,所以我们不知道哪个进程运行结束的更早,也就不知道具体的输出顺序
 
 题目2:
 int main()
              {
  pid_t n;
               for(int i=0;i<2;i )
               {
                 if(fork())
                 {
                    printf("A");
                  }
else
                {
                   printf("B");
                 }
               }
        如果我们每次输出不执行'\n'会发生什么呢?

       题目3:
      
       int main()
              {
  pid_t n;
               for(int i=0;i<2;i )
               {
                 if(fork())
                 {
                    printf("A\n");
                  }
else
                {
                   printf("B\n");
                 }
               }
      这样又会输出什么呢?
大家可以先想一下这两个思考题,如果想不到,请看下回分解。