【Linux学习笔记】标准IO缓冲:行缓冲、全缓冲、无缓冲

首先介绍一下UNIX里面关于标准IO的几种缓冲机制
  • 全缓冲 :全缓冲指的是系统在填满标准IO缓冲区之后才进行实际的IO操作;注意,对于驻留在磁盘上的文件来说通常是由标准IO库实施全缓冲。

  • 行缓冲 :在这种情况下,标准IO在输入和输出中遇到换行符时执行IO操作;注意,当流涉及终端的时候,通常使用的是行缓冲。

  • 无缓冲 :无缓冲指的是标准IO库不对字符进行缓冲存储;注意,标准出错流stderr通常是无缓冲的。

通过系统调用和库函数认识IO缓冲

先看一段代码:

#include 
#include 

int main()
{
    const char *msg0 = "hello printf\n";
    const char *msg1 = "hello fwrite\n";
    const char *msg2 = "hello write\n";

    printf("%s", msg0);
    fwrite(msg1, strlen(msg0), 1, stdout);
    write(1, msg2, strlen(msg2));

    fork();

    return 0;
}

【运行结果】:
hello printf
hello fwrite
hello write

对进程实现重定向:./test > file,

【运行结果】:
hello write
hello printf
hello fwrite
hello printf
hello fwrite

printf和fwrite(库函数)都输出了2次,而write只输出了一次(系统调用)。这是因为fork。

  • 一般C库函数写入文件是全缓冲的,而写入显示器是行缓冲。
  • printf和fwrite库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。
  • 而我们放在缓冲区中的数据,不会立即被刷新,甚至fork之后,但是进程退出之后,会被统一刷新,写入文件当中。
  • fork的时候,父子数据会发生写时拷贝,所以当父进程准备刷新的时候,子进程也就有了同样的一份数据,随既产生两份数据。
  • write没有变化,说明没有所谓的缓冲

因此,缓冲取是库函数在系统调用的“上层”,是对系统调用的“封装”。

再来看几个退出函数
  • exit ():调用exit函数之后,它首先会执行一系列的清理处理,包括调用执行各终止处理程序,关闭所有标准IO流等,然后进入内核。

  • _exit ():与exit不同的是,它不进行清理工作而直接进入内核。此函数由POSIX.1说明,放在unistd.h里面。

我们通过代码来看一下

#include 
int main()
{
    printf("hello world!");
    _exit(0);
}

本来想打印hello world,但是终端没有显示。

#include 
int main()
{
    printf("hello world!");
    exit(0);
}

【运行结果】:
hello world!

由于printf函数是行缓冲的(因为它要往终端输出数据),而且要打印的字符串不带换行符,因此在它没有遇到换行符或者没有填满缓冲区之前不会进行实际的IO操作,而在_exit函数有立即进入内核没有处理IO缓冲区,所以我们在终端上看不到hello world语句。当我们调用exit()函数时,在终端看到了hello world

【Linux学习笔记】标准IO缓冲:行缓冲、全缓冲、无缓冲_第1张图片

你可能感兴趣的:(linux)