我正在尝试以下C代码:
int main()
{
printf("text1\n");
fork();
printf("text2\n");
return 0;
}
我期待得到输出,我得到两个“text1”和两个“text2”,如:
text1
text1
text2
text2
但是,相反,我得到了:
text1
text2
text2
只有一个“text1”??? 好吧,如果子进程从fork()执行,那么为什么我得到两个“text1”用于跟随:
int main()
{
printf("text1");
fork();
printf("text2\n");
return 0;
}
现在的输出是:
text1text2
text1text2
如果子进程在fork之后开始,则输出应为:
text1
text2
text2
答案 0 :(得分:24)
fork()
通过将当前流程中的所有内容复制到新流程中来创建新流程。这通常包括内存中的所有内容以及CPU寄存器的当前值以及一些小的调整。所以实际上,新进程也会获得进程指令指针的副本,因此它会在原始进程继续的同一点(fork()
之后的指令)恢复。
为了解决您的更新问题,printf()
已缓存。通常,缓冲区在最后遇到换行符'\n'
时被刷新。但是,由于您省略了这一点,缓冲区的内容会保留并且不会被刷新。最后,两个进程(原始进程和子进程)都将具有"text1"
的输出缓冲区。当它最终被刷新时,你会在两个过程中看到这一点。
实际上,在分叉之前,应始终刷新文件和所有缓冲区(包括stdout
),以确保不会发生这种情况。
printf("text1");
fflush(stdout);
fork();
输出应该如下所示(按某种顺序):
text1text2 text2
答案 1 :(得分:7)
forked进程获取变量内存的副本,并且在fork时,输出缓冲区尚未被刷新。 fork时没有输出写入控制台,只是缓冲了。因此,两个进程都继续使用text1已经在缓冲区中,因此都打印它。
答案 2 :(得分:6)
fork
克隆当前进程。新流程将在fork
来电时“开始”,而不是在main
的开头,正如您所期待的那样。因此,当您第一次打印时有1个进程,那么当您分叉时有两个进程。
由于您在打印fork
后"text1"
,因此仅打印一次。
在第二个例子中,重复的输出是由于输出缓冲 - printf实际上并没有输出任何东西到屏幕,直到它被刷新或它到达换行符('\n'
)。
因此,对printf
的第一次调用实际上只是将数据写入某个缓冲区,然后将数据复制到第二个进程的地址空间,然后对printf
的第二次调用将刷新缓冲区,在两个缓冲区中都有"text1"
。
答案 3 :(得分:2)
这是因为fork
ed进程在fork
之后开始,而不是从一开始就开始。 exec
从入口点开始处理,并打印出您期望的内容。
答案 4 :(得分:1)
子进程将从fork()的位置开始,因此您将获得正确的输出。
答案 5 :(得分:1)
Problem 1 : the output as text1 text2 text2
Problem 2 : the output as text1text2 text1text2
答案 6 :(得分:0)
来自man 2 fork
:fork将0返回到子进程。
value = fork();
if( value == -1 ) {
printf( "fork failed\n" );
exit(1);
}
if( value ) {
printf( "test1\n" );
} else {
printf( "test2\n" };
}