编译执行: $gcc -o test test.c $./test Start fork...Child process. Start fork...Parent process. 出乎意料的是,为什么"Start fork..."输出了两次呢?子进程是从fork之后的语句开始执行的,那么多出来那个"Start fork..."是哪里来的呢? 先了解一下缓冲区: 这个缓冲区既不是内核中的缓冲区,也不是用户分配的缓冲区,而是有编译器维护的用户进程空间中的缓冲区.缓冲区类型有:全缓冲(大部分缓冲都是这类型)、行缓冲、无缓冲。 标准里没有规定各种流是什么缓冲,stderr和stdout是哪种缓冲类型是和环境相关的。 stderr 可能是无缓冲、行缓冲,但不能是全缓冲。stdin 和 stdout 可能是无缓冲、行缓冲,也可能是全缓冲。不过,stdin 和 stdout 如果分别是指键盘和显示器等交互设备(interactive device)的话,那么只能是无缓冲或行缓冲。 默认情况下,printf()在屏幕输出的时候是行缓冲的,所以父进程在执行了第一个printf语句后,"Start fork..."还保存在缓冲区中,执行fork的时候,父进程缓冲区的数据也被复制到子进程中,子进程在刷新缓冲区的时候,输出了从父进程复制来的"Start fork..."。 下面对程序进行一些修改: 1、如果把第7句改为: fprintf(stdout,"%s","Start fork...\n");$./test Start fork... Child process. Parent process. 说明当前环境下printf是行缓冲的。 把修改过的程序的执行结果重定向到文件中: $./test > temp $cat temp Start fork... Child process. Start fork... Parent process. 这说明将printf输出结果重定向到文件的时候就变了全缓冲. 2、如果在第7行以后加入一句: $./test > temp $cat temp Start fork... Child process. Parent process. 我们用fflush强制刷新缓冲区,这样父进程缓冲区被清空。我们在fork之前一般都要用fflush(NULL)清空所有流。 3、我们把第7句改为: fprintf(stderr,"%s","Start fork...");$./test > tempStart fork... $cat temp Child process. Parent process. 把修改过的程序的执行结果重定向到文件,把标准错误重定向到标准输出: $./test > temp 2>&1 $cat temp Start fork... Child process. Parent process. ; 设置标准输出为无缓冲。 $./test > temp $cat temp Start fork... Child process. Parent process. |