Linux缓冲机制

Linux缓冲简介


Linux提供了无缓冲和缓冲的IO操作函数。

原生的IO例程readwritelseekclose是无缓冲的。

而标准的IO库freadfwritefseekfclose则是带缓冲的。

无缓冲是指由开发人员自己传递读写的数据和大小,如果设置传递的数据太小,例如每次读写一个char,那么1M的文件将可能产生一百万次的系统调用,这样效率非常慢。所以程序员要设置好buffer的值,已达到最好的效率,通常将数据大小设置为文件系统的块大小,一般为4K。(虽然用户层不缓冲,但是内核存在缓冲

而标准库函数是带缓冲的,实际上是对IO例程的封装,通过在用户层缓冲来减少系统调用的次数。

Linux缓冲机制


  1. 全缓冲:全缓冲指的是系统在填满标准IO缓冲区之后才进行实际的IO操作;注意,对于驻留在磁盘上的文件来说通常是由标准IO库实施全缓冲。

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

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

缓冲验证程序1


1
2
3
4
5
6
7
8
9
10
//buffer1.c
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("before fork\n");
fork();
return 0;
}
  • 使用./buffer1运行该程序的时候,输出结果是:
1
before fork

行缓冲是当遇到换行符或者缓冲满了的时候才进行实际的IO操作,程序中用了换行符,那么在创建子进程前父进程输出一次缓冲输出并清空缓冲,此时子进程不会再输出。

若改为printf("before fork");则输出两次。

  • 使用./buffer1 > a.txt运行该程序的时候,文件中的输出结果是:
1
2
before fork
before fork

对于磁盘中的文件通常是实施全缓冲,所以子进程创建以后还会输出缓冲区的内容一次。

缓冲验证程序2


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
int i;
for(i=0;i<2;i++)
{
fork();
printf("-");
}
sleep(10);
return 0;
}

程序输出结果是什么?

很多人以为是6个-,但答案是8个-

解析
程序进行两次循环。

第一次父进程fork一个子进程,这时候父进程和子进程都输出一个-,共2个。

第二次父进程再次fork一个子进程,此时父进程继续输出一个-,而由于之前没有清空缓冲,故这次由父进程创建的子进程会输出两个-。共3个。

对于第一次创建的子进程也是同理。共3个。

所以一共输出的-为8个。

如果将程序对应语句改为printf("-\n");则输出6个。