zoukankan      html  css  js  c++  java
  • fork与文件描述符、标准I/O

    Unix/Linux编程实践教程 有两道习题8.4/8.5

    main() 
    { 
        int fd; 
        int pid; 
     
        char msg1[]="Test 1 2 3 ..
    "; 
        char msg2[]="Hello, hello
    "; 
     
        fd=creat("testfile",0644); 
        write(fd,msg1,strlen(msg1)); 
        pid=fork(); 
        write(fd,msg2,strlen(msg2)); 
     
        close(fd); 
    }

    8.4输出是:

    Test 1 2 3 ..
    Hello, hello
    Hello, hello

    但是:

    main()
    {
        FILE *fp;
        int pid;
    
        char msg1[]="Test 1 2 3 ..
    ";
        char msg2[]="Hello, hello
    ";
    
        fp=fopen("testfile2","w");
        fprintf(fp,"%s",msg1);
        pid=fork();
        fprintf(fp,"%s",msg2);
    
        fclose(fp);
    }

    8.5输出是:

    Test 1 2 3 ..
    Hello, hello
    Test 1 2 3 ..
    Hello, hello

    分析:

    先来看下“STDOUT_FILENO”和“FILE *stdout”的区别:
    stdin / stdout / stderr是FILE*类型,供标准C++一级提供的文件操作函数库使用,定义在头文件<stdio.h>中。
    STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO 是int类型,其实质是文件描述符(值分别为0,1,2),定义在头文件<unistd.h>中。
    FILE * stdin / stdout / stderr 对应的文件描述符(fd)分别是 STDIN_FILENO(0) / STDOUT_FILENO(1) / STDERR_FILENO(2) 。
    两者的差别主要是标准I/O是带缓冲(具体见下面说明)的,而STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO是不带缓冲的。
     
    我们只需记住:
    使用stdin / stdout / stderr的函数主要有:fread、fwrite、fclose等,基本上都以f开头。
    使用STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO的函数有:read、write、close等。
     
    下面看下关于"printf"/"write"和缓冲的说明:
    printf是在stdio.h中声明的函数,而标准IO都是带缓冲的,所以printf是带缓冲的。而write则是不带缓冲的。
    标准IO在输入或输出到终端设备时,它们是行缓冲的,否则(文件)它们是全缓冲的。而标准错误流stderr是不使用缓冲的。更为准确的描述是:当且仅当标准输入和标准输出并不涉及交互式设备使,他们才是全缓冲的。标准出错流不使用缓冲。
    下列情况会引发缓冲区的刷新(清空缓冲区):
    1、缓冲区满时;
    2、执行flush语句;
    3、执行endl语句(printf是" ");
    4、关闭文件
    综上所述,8.5的代码在主线程因为关闭文件才将字符全部输出到文件中,因此文件所有内容都是两份,而类比forkdemo1.c情况,代码执行情况都是一样的,msg1这句已经执行,但是内容在缓冲区中并未被输出,直到碰见关闭文件才将内容全部输出。
     
    “上图来自The Linux Programming Interface - 5.5 Duplicating File Descriptors”

    进程A的fd1和fd20这种就是dup类系统调用的结果,
    进程A的fd2和进程B的fd2就是fork的结果(fork之后指向相同的文件),
    进程A的fd0和进程B的fd3最终指向同一个inode,这是这两个进程都调用过open的结果,此时两个文件不共享文件内的偏移,
    文件偏移是存放在第二个表中的,所以不管是dup还是fork,都是共享同一组偏移.

    将程序改为:增加一行fflush

    main()
    {
        FILE *fp;
        int pid;
    
        char msg1[]="Test 1 2 3 ..
    ";
        char msg2[]="Hello, hello
    ";
    
        fp=fopen("testfile2","w");
        fprintf(fp,"%s",msg1);
        fflush(fp);
        pid=fork();
        fprintf(fp,"%s",msg2);
    
        fclose(fp);
    }

    输出结果两者就是一样的。 

    参考资料:

    关于fork之后父子进程的文件描述符关系有些疑问?-Linux环境编程-ChinaUnix.net

    http://bbs.chinaunix.net/thread-4166362-1-1.html

    Linux学习之"fork函数" - lq0729 - 博客园

    http://www.cnblogs.com/lq0729/archive/2011/10/24/2222536.html

  • 相关阅读:
    software 的魅力
    CSS中,脚本不能覆盖CSS的!!!
    取消自增ID.
    [求教]FF与IE 的Style 不兼容问题?
    SQL存储过程 之 sp_MSforeachtable和sp_MSforeachDB
    疑问:AddWebPart 不能添加动态加载的自定义控件吗?
    关于 各语言的 readonly。
    查询存储过程中的结果集.(顺便贴:一行折多行的方法)
    附一张css hack
    远程桌面dos开启
  • 原文地址:https://www.cnblogs.com/daijkstra/p/5138524.html
Copyright © 2011-2022 走看看