日期:2014-05-16  浏览次数:20880 次

linux下fork()函数在行缓冲和全缓冲情况下对IO的影响

行缓冲:

当标准IO连接到输出设备的时候,它是行缓冲的(比如输出到终端屏幕等),否则它是全缓冲的.


区别:

行缓冲每输出一行,清空一次缓冲区.

全缓冲在文件结束时,例如fclose()关闭文件时,才清空缓冲区.



不带缓冲的IO对fork()执行期间的影响


标准IO要经过内核的块缓冲区,原始的磁盘IO与其相反.比如read(),write()等.所以不带缓冲的磁盘IO无论在行缓冲还是全缓冲的情况下都不会在子进程缓冲区中存在.


标准IO对fork()执行期间的影响

当父进程通过fork()函数启动一个子进程的时候,会复制父进程的数据空间,堆,栈和副本,这其中也包括了父进程的缓冲区.


行缓冲情况下:

子进程在执行标准io操作的时候会输出父进程复制过来的缓冲区中的内容.由于行缓冲区会被清空,所以不会对子进程的标准IO产生影响.


全缓冲情况下:

子进程产生父进程缓冲区中的副本,再执行标准IO时会先输出父进程缓冲区中复制过来的副本的内容,所以在使用标准IO之前,可以通过清空文件缓冲区的操作,来不影响子进程的标准IO.


下面通过一个APUE中的实例来展示他们之间的区别


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

int glob = 6;
char buf[] = "a write to stdout\n";

int main()
{
    int     var;
    pid_t   pid;

    var = 88;
    if ((write(STDOUT_FILENO, buf, sizeof(buf)-1)) != sizeof(buf)-1)
        printf("write error\n");

    printf("before fork\n");
    if ((pid = fork()) < 0) {
        printf("fork error\n");
    } else if (pid == 0) {
        glob++;
        var++;
    } else {
        sleep(2);
    }

    printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
    return 0;
}


运行结果:


1.行缓冲

android@startos:~$ ./a.out
a write to stdout           //不带缓冲的IO
before fork                 //行缓冲
pid = 4067, glob = 7, var = 89
pid = 4066, glob = 6, var = 88


2.全缓冲

android@startos:~$ ./a.out > tempfile.out
android@startos:~$ cat tempfile.out
a write to stdout               //不带缓冲的IO,只输出了一次
before fork                     //fork()调用之前输出的"before fork"
pid = 4087, glob = 7, var = 89
before fork                     //全缓冲时,子进程从父进程缓冲区中复制过来的 "before fork"
pid = 4086, glob = 6, var = 88