天天看点

关于linux下fork()函数的解析:子进程继续创建子进程,如何停止?

先贴代码:

for(i = 0; i < 4; i++)
{
    fork();
    printf("a\n");
}
           

问:一共输出多少个a?  答:30个(2+4+8+16)

先说下思路:父进程创建子进程后,fork函数是让子进程完全拷贝父进程,包括父进程上下文,什么意思呢?就是说父进程的EIP(CPU的下一条指令地址)以及变量等等一律拷贝,也就是说,父进程执行过的代码子进程是不会再执行,子进程下一条该执行的命令与父进程完全一样!!!

解析:

i=0时;fork()后,产生一个子进程,然后父子进程共同printf各1次;共两次;

之后,父子进程都进入i=1:

  • 父子进程都会fork,也就是父进程fork了一个新的子进程;i=0的子进程也fork了一个子进程,共4个进程,每个进程都继续往下执行,也就是printf一次;共4次

以此类推:也就是2+4+8+16=30次。具体看下图:

关于linux下fork()函数的解析:子进程继续创建子进程,如何停止?

共打印30次

fork会让子进程拷贝一切父进程的信息,包括这里面的变量i的值,所以子进程不会一直循环的fork下去,在i=2时,子进程(称为p2吧)fork出p3,然后p2继续执行printf,fork后创建的p3子进程的执行位置也和p2一样为printf,同时该创建的p3子进程自然下一次循环是从i=3开始,当i=3完成之后,i变成4,所有由总父进程创建出来的子进程都同时结束。

第二题

请问下面的程序一共输出多少个”-”?

1

2

3

4

5

6

7

8

9

int main(void)

{

int i;

for(i=

;i<

2

;i++){

fork();

printf(

"-"

);

}

return 

;

printf是一个行缓冲函数,先写到缓冲区,满足条件后才将缓冲区刷新到对应文件中,刷新缓冲区的条件如下:

    1)缓冲区填满;

    2)写入的字符中有‘\n’、'\r';

    3)调用fflush手动刷新缓冲区;

    4)调用scanf要从缓冲区读取数据时,也会将缓冲区内的数据刷新。

另外,当执行printf的进程或线程结束的时候,也会主动调用flush来刷新缓冲区。

本题中printf没有'\n',是因为进程执行结束,才去刷新缓冲区,在屏幕上显示字符,这是理解本题的关键。

关于linux下fork()函数的解析:子进程继续创建子进程,如何停止?

当i=1时,parent进程中printf的缓冲区内容为"--",第一个'-'为i=0时printf的输出,只是没有'\n'而囤积到这一次。child2进程中printf缓冲区的第一个'-'则是因为子进程会复制父进程的缓冲区,因此复制了parent的buf。

需要注意的是i=0时的缓冲区之所以不打印,是因为这两个缓冲区跟i=1时的缓冲区是共用的一个,其中parent和child1缓冲区都到了i=1了,也就是本程序只有4个缓冲区,最后4个缓冲区都被刷新打印出来了,如图所示。

程序结束即所有进程都结束后,会自动刷新缓冲区,此时会一下子把parent,child2,child1和child1_2的缓冲区输出到显示屏幕上,输出的顺序可能会随机。因此最后共输出8个'-'。