场景:父进程trace进程A,当A进程fork子进程B时,让父进程也fork子进程去trace子进程B,用于trace的进程将被trace的进程发生的系统调用号通过fprintf存入各自文件中

问题:printf输出正确,而fprintf到文件的内容会重复(其实就知道了是缓冲问题)

解决:在调用fork()前用fflush(fp);清空文件缓冲区

原因:在fork()的调用处,整个父进程空间会被复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。

延伸到stdio缓冲区:stdio缓冲区在进程的用户空间内存中,通过fork()创建的子进程会复制这些缓冲区,当标准输出定向到终端时,因为缺省为行缓冲,所以会显示printf输出的包含换行符的字符串。

不过,当标准输出重定向到文件时,由于缺省块缓冲,所以调用fork()时,printf()输出的字符串仍然在父进程的缓冲区中,并随子进程的创建而产生一份副本。

父,子进程调用exit()时会刷新各自stdio缓冲区,从而导致重复输出的结果。

知识:

标准I/O库提供了三种类型的缓冲:

(1) 全缓冲:填满标准I/O缓冲区才实际进行I/O操作。

(2)行缓冲:在输入和输出中遇到换行符时,标准I/O库执行I/O操作,当流涉及终端时,通常使用行缓冲。

(3)不带缓冲:标准出错流stderr通常是不带缓冲的。

上面说的缓冲指的是应用层的缓冲,在进行实际的I/O操作时,相关的系统调用(read和write)其实在内核也有缓冲区的。

当输出到终端时,由于是行缓冲,所以遇到换行符'\n'后缓冲区被冲洗。

当将程序输出重定向到文件时,标准输出是全缓冲,fork之前printf的数据仍在缓冲区中,在fork时该缓冲区也被复制到子进程中,因此输出两次。

实验:

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h> int main()
{
FILE *fp = fopen("./1.txt", "wt+");
if(fp == NULL)
{
return -;
}
printf("xxx\n");
fprintf(fp, "%d\n", );
//fflush(fp);//调用fork()之前使用函数fflush()来刷新stdio缓冲区
if(!fork())
{
exit();
//_exit(0);//子进程调用_exit(0)而非exit()以不再刷新stdio缓冲区
} return ;
}

1、输出到终端(行缓冲)

2、重定向到文件xxx.txt(块缓冲)

3、fprintf到文件1.txt(fprintf函数在默认情况下只有当缓冲区达到一定条件或是程序自然停止时才会输出数据到文件)

可以看到2和3都重复输出,用上面注释的方法即可解决该问题

概念参考:

https://blog.csdn.net/dextrad_ihacker/article/details/52033223

http://www.cnblogs.com/tonychen-tobeTopCoder/p/5335452.html

文件缓冲区在fork后复制的更多相关文章

  1. fork后父子进程文件描述问题

    [fork后父子进程文件描述问题] 一张图可以浅析的解释: 参考:http://wenku.baidu.com/view/dd51581bff00bed5b9f31d8e.html

  2. IOSerialize,xml和json,soap序列化器,二进制序列化器,XML序列化器,文件 检查、新增、复制、移动、删除

    1 文件夹/文件 检查.新增.复制.移动.删除,2 文件读写,记录文本日志/读取配置文件3 三种序列化器4 xml和json1.文件夹/文件 检查.新增.复制.移动.删除,2 文件读写,记录文本日志/ ...

  3. IO流,字节流复制文件,字符流+缓冲复制文件

    JAVAIO如果按流向分:输入流和输出流两种 输入流的基类:InputStream   Reader 输出流的基类:OutputStream   Writer 如果按数据单元划分:字节流和字符流 字节 ...

  4. github fork后的pull和保持同步

    前言 对github上的某个项目贡献自己的修改,但自己可能并没有那个仓库的权限,那要如何操作呢?git的机制和svn还是有些区别的,本文做些记录. 思路1 clone项目到本地,有修改之后,直接提交到 ...

  5. Web 在线文件管理器学习笔记与总结(13)重命名文件夹(14)复制文件夹

    (13)重命名文件夹 ① 重命名文件夹通过 rename($oldname,$newname) 实现 ② 检测文件夹名是否符合规范 ③ 检测当前目录中是否存在同名文件夹名称,如果不存在则重命名成功 i ...

  6. 每次调用fork()函数之后,父线程和创建出的子线程都是从fork()后开始执行

    Linux下多少个"-"将被打印: 1 2 3 4 5 6 7 8 int main(void){   int i;   for(i=0;i<4;i++){   fork() ...

  7. c# 封装的文件夹操作类之复制文件夹

    c#  封装的文件夹操作类之复制文件夹 一.复制文件夹原理: 1.递归遍历文件夹 2.复制文件 二.FolderHelper.cs /// <summary> /// 文件夹操作类 /// ...

  8. 用winscp从本地上传文件到服务器上出现复制文件到远端时错误。

    用winscp从本地上传文件到服务器上出现复制文件到远端时错误. 错误码:4 服务器返回的错误消息:write failed 报错如下图所示: 分析过程: 1.刚开始以为是权限不够,后面上网查了一下是 ...

  9. 将目录下面所有的 .cs 文件合并到一个 code.cs 文件中,写著作权复制代码时的必备良药

    将目录下面所有的 .cs 文件合并到一个 code.cs 文件中,写著作权复制代码时的必备良药 @echo off echo 将该目录下所有.cs文件的内容合并到一个 code.cs 文件中! pau ...

随机推荐

  1. Linux软件包安装

    rpm命令 命名方式  name-VERSION-release.arch.rpm 常见的arch: x86:   i386  i486    i586   i686 x86_64:   x64    ...

  2. GPT转MBR怎么转?

    GPT转MBR分区怎么转?现在很多笔记本的硬盘分区都是GPT模式,如果想装XP的话,那只能将GPT磁盘转换成MBR磁盘分区才行.接下来,简单说说如何将GPT分区转成MBR分区! 如果本身电脑有两个硬盘 ...

  3. Redis入门到高可用(十)—— Spring与Redis的整合

    1.pom文件 <!--redis--> <dependency> <groupId>org.springframework.data</groupId> ...

  4. nodejs, vue, webpack 项目实践

    vue 及 webpack,均不需要与nodejs一期使用,他们都可以单独使用到任何语言的框架中. http://jiongks.name/blog/just-vue/ https://cn.vuej ...

  5. 多线程——Executor、ExecutorService、Executors三者的区别

    Executor.ExecutorService.Executors三者的区别: 层次关系: public interface ExecutorService extends Executor {} ...

  6. php使用solr全文搜索引擎

    前言 本来以为网上已经有了类似博文,不想重复,可是一圈搜下来,都是一些内容不甚明了的文章,或者solr版本太过老,参考价值不高,更有甚者,直接拷贝的别人的内容.一篇博客,各大平台都能看到,也不见转载链 ...

  7. 常量,变量,a++,++a,+=等

    常量:数据在程序里面进行运算时不能发生改变的数据,成为常量.变量:可变动的数据.变量的定义:  数据类型   变量名   =  初始值.基本数据类型:整数型:byte              1字节 ...

  8. 亚马逊IOT-SDK,线程池数

    1111

  9. 【LeetCode每天一题】 Merge k Sorted Lists(合并K个有序链表)

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. E ...

  10. jenkins 常见问题汇总

    1.jenkins api调用 https://my.oschina.net/sanpeterguo/blog/197931 其中,有个错误的地方,带参数构建时,使用的时POST方法,如下: curl ...