2012-05-22 76 views
6

我正在试验fork()并重新检查是否在父项中重做的方向也适用于孩子。我写了下面的简单程序fork()打印两次之前的声明

#include<stdio.h> 
#include<unistd.h> 
#include<stdlib.h> 

int main() 
{ 
    freopen("error.txt", "w+t", stdout); // From now on, stdout = error.txt 
    printf (" ERROR! WHY DONT U UNDERSTAND?\n"); 
    if (fork() == 0) 
    { 
     printf(" I AM CHILD\n"); 
     exit(0); 
    } 
    else- 
    { 
     printf (" EITHER I AM A PARENT OR SOMETHING GOT SCREWED\n"); 
    } 


    return 0; 
} 

输出(error.txt)我是

ERROR! WHY DONT U UNDERSTAND? 
EITHER I AM A PARENT OR SOMETHING GOT SCREWED 
ERROR! WHY DONT U UNDERSTAND? 
I AM CHILD 

出人意料的是,ERROR! WHY DONT U UNDERSTAND?打印两次fork()被调用,应该即使它看起来多少只能由父母打印一次。

任何人都可以对此有所了解吗?

+0

我不确定这个,但确保你在fork之前刷新io-buffers。也许缓冲区被复制到孩子。 – lupz

+2

这将成为一个优秀的面试问题! – dasblinkenlight

回答

10

由于在reopen之后该流是非交互式的,因此它是完全缓冲的,并且在'\n'上没有刷新。在调用fork之前,缓冲区仍包含消息,并且在fork之后,此缓冲消息被复制(因为两个进程都获得了自己的stdout副本),然后由父级和子级刷新。参见C标准的第7.19.3部分。

您可以通过在fork之前拨打fflush来避免此类行为。

+0

我知道'\ n'在重定向后不能用作自动冲洗器。谢谢,+1 –

+0

你也可以使用'setvbuf'来重新配置'stdout'。 –

3

这是因为缓冲。在printf之后执行fflush

这两个过程最终都会得到stdio的内部副本,并且都会在exit处进行刷新。如果您在小孩中拨打_exit,您也可以防止它发生。

+0

如果我将'exit()'更改为'_exit()',那么孩子不会打印任何东西。即输出中缺少'I AM CHILD'。 'exit()'和'_exit()'有什么区别? –

+1

@Stacker'_exit'不刷新stdio缓冲区。 – cnicutar

1

冲洗缓冲区将解决问题。 在打印语句后面使用fflush。

0

似乎ERROR! WHY DONT U UNDERSTAND仍然在分叉后被缓冲,并被两个进程写入。

如果您的权利后,你的第一printf()内部缓冲区被刷新,而且只在您的文件中出现一次加

fflush(stdout);