关于fork多进程中printf的问题
程序1
int main(int argc, char **argv)
{
int remaining = 4;
int child_pid;
while (remaining > 0)
{
child_pid = fork();
if (child_pid == 0) break;
remaining--;
}
printf("P");
return 0;
}
上面的程序将输出:PPPPP
(5个P)
程序执行过程:
-
remain = 4,
父进程(P0):进入while循环,创建子进程(P1),
remain--
子进程(P1):执行语句
if (child_pid == 0) break
,退出循环,打印P
-
remain = 3,
父进程(P0):进入while循环,创建子进程(P2),
remain--
子进程(P2):执行语句
if (child_pid == 0) break;
,退出循环,打印P
-
remain = 2,
父进程(P0):进入while循环,创建子进程(P3),
remain--
子进程(P3):执行语句
if (child_pid == 0) break;
,退出循环,打印P
-
remain = 1,
父进程(P0):进入while循环,创建子进程(P4),
remain--
子进程(P4):执行语句
if (child_pid == 0) break;
,退出循环,打印P
-
remain = 0,
父进程(P0):退出while循环,打印
P
程序2
int main(int argc, char **argv)
{
int remaining = 4;
int child_pid;
while (remaining > 0)
{
child_pid = fork();
remaining--;
}
printf("P");
return 0;
}
上面的程序将输出:PPPPPPPPPPPPPPPP
(16个P)
程序执行过程:
-
remain = 4,
父进程(P0):进入while循环,创建子进程(P1),
子进程(P1):
remain--
-
remain = 3,
父进程(P0):进入while循环,创建子进程(P2),
子进程(P1):进入while循环,创建子进程(P3)
子进程(P2),子进程(P3):
remain--
-
remain = 2,
父进程(P0):进入while循环,创建子进程(P4),
子进程(P1):进入while循环,创建子进程(P5),
子进程(P2):进入while循环,创建子进程(P6),
子进程(P3):进入while循环,创建子进程(P7),
子进程(P4),子进程(P5),子进程(P6),子进程(P7):
remain--
-
remain = 1,
父进程(P0):进入while循环,创建子进程(P8),
子进程(P1):进入while循环,创建子进程(P9),
子进程(P2):进入while循环,创建子进程(P10),
子进程(P3):进入while循环,创建子进程(P11),
子进程(P4):进入while循环,创建子进程(P12),
子进程(P5):进入while循环,创建子进程(P13),
子进程(P6):进入while循环,创建子进程(P14),
子进程(P3):进入while循环,创建子进程(P15),
子进程(P8),子进程(P9),子进程(P10),子进程(P11),子进程(P12),子进程(P13),子进程(P14),子进程(P15):
remain--
-
remain = 0,
父进程(P0),子进程(P1),子进程(P2),子进程(P3),子进程(P4),子进程(P5),子进程(P6),子进程(P7),子进程(P8),子进程(P9),子进程(P10),子进程(P11),子进程(P12),子进程(P13),子进程(P14),子进程(P15):退出while循环,打印
P
程序3
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int remaining = 4;
int child_pid;
printf("P"); // printf在此处
while (remaining > 0)
{
child_pid = fork();
if (child_pid == 0) break;
remaining--;
}
return 0;
}
程序4
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int remaining = 4;
int child_pid;
printf("P\n"); // printf在此处,且在"P"后加上换行符\n
while (remaining > 0)
{
child_pid = fork();
if (child_pid == 0) break;
remaining--;
}
return 0;
}
程序3输出:PPPPP
(5个P)
程序4输出:P
(1个P)
原因分析:
-
printf是向标准输出(
stdout
)输出想要打印的东西,而默认的stdout
是行缓存line buffering
的,所以当打印的东西不够一行的时候(没有\n
),这些信息是保存在stdout
的buffer
中。 -
fork()
时,子进程会复制父进程的所有资源,做到和父进程一样,也包括了缓冲区。如果在fork()
前刷新了缓冲区,也就是在printf
中使用换行符\n
,那么在fork()
前,信息就会被打印出来,fork()
之后父进程和子进程stdout
的buffer
中都是空的了。
同理,如果注释掉if (child_pid == 0) break;
,程序4将输出16个P。
程序5
int main()
{
for (int i = 0; i < 3; i++)
{
fork();
printf("*\n");
}
return 0;
}
程序6
int main()
{
for (int i = 0; i < 3; i++)
{
fork();
printf("*");
}
return 0;
}
程序5输出:(14个*
)
程序6输出:************************
(24个*
)
原因分析:
- 程序5中每次
printf
都会刷新缓冲区,具体示意图如下:
- 程序6中的
printf
没有刷新缓冲区,fork
时子进程会复制父进程的缓冲区