当fork遇见for循环,printf后会怎样?
这段时间总看见这种题,今天总结一下。
题1
先看代码1:
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int main()
{
printf("1 2 3");
fork();
}
代码2:
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int main()
{
printf("1 2 3\n");
fork();
}
以上两段代码基本一样,不一样的就是‘\n’,我们自然能想到缓冲区的问题。
printf
这条命令处理起来却应该分为两步:
- 系统将printf()中传进的数据写进进程的缓冲区
- 对于标准输出而言(行缓冲),系统判断如果缓冲区中有“\n”,或是EOF,或是主动刷出,或是缓冲区满,或是文件描述符关闭,或是exit,就会把数据从缓冲区中输出出来(flush)
也就是说对于printf()代表的行缓冲而言,数据只是先被存储在了缓冲区,直到碰见上述情况才会输出。如果缓冲区内有内容,当进程退出时(exit)也会自动进行输出。
我们再来看这两段代码,我们先看一下结果:
代码1:
代码2:
结果分析
代码1中主进程的缓冲区因为执行时没有输出条件,所以内容被子进程继承,两个进程结束时触发exit,输出缓冲区内容,结果为
1 2 3 1 2 3
而代码2因为执行时有’\n’条件所以主进程输出1 2 3后缓冲区刷空,子进程继承来空的buffer自然无输出,结果为
1 2 3
题2
基于题一的知识,我们看题2。
代码1:
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int main()
{
int i=0;
for(i=0;i<2;i++)
{
fork();
printf("-");
}
return 0;
}
代码2:
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int main()
{
int i=0;
for(i=0;i<2;i++)
{
fork();
printf("-\n");
}
return 0;
}
结果:
代码1:
代码2:
基于题一的解释,应该各输出几个-呢?
题中,有两层循环:
(1)一次循环后有两个进程,
代码1中主进程的缓冲区因为执行时没有输出条件,所以内容被子进程继承,此时两个进程的缓冲区各有一个’-’ 。
代码2中因为有执行条件’\n’,所以主进程和子进程各打印出一个’-’
(2)第二次循环后,两个进程分别fork出各自的子进程,所以共四个进程,
代码1中,同理,fork出的子进程继承父进程的缓冲区,此时四个进程的缓冲区都有’-‘,再次执行printf,各自的缓冲区都多了一个’-‘,结束时触发exit,输出缓冲区内容,结果为8个。
而代码2中,四个进程缓冲区为空,执行printf,打印四个,共6个。
题三
看代码,共有多少个进程数?
#include<stdio.h>
int main()
{
fork();
fork()&&fork()||fork();
fork();
}
我们需要知道几个问题:
- 父进程fork出子进程,子进程从fork后面那个指令开始执行的
- fork后父进程返回子进程PID,子进程返回0
- 对于”a&&b”表达式,如果a为0,b就不会执行
(1)第一次fork,进程A变成A和其子进程B
(2)fork()&&fork()||fork();
分析如下图:
注意:
C和D都是子进程,那么它俩返回的值都是0,因此”&&”后面的表达式就不会执行,之后执行最后一个fork()函数。
但是A和B两个父进程返回值大于0,因此会执行后面的”fork()||fork()”
(3)最后一次fork
所以带最开始的A进程,共20个进程。