文章目录
三种缓存类型
标准 I/O 库提供缓冲的目的就是尽可能的减少系统调用,从而提高 I/O 操作的效率。标准的 I/O 操作提供了三种类型的缓冲:全缓冲、行缓冲和不带缓冲;
- 全缓冲: 在填满标准 I/O 缓冲区后才进行实际的 I/O 操作;
- 例如:对于驻留在磁盘上的文件,就是进行全缓冲操作;
- 全缓冲可以由 I/O 自动冲洗;
- 全缓冲也可以用
fflush
冲洗一个文件流;
- 行缓冲: 在填满标准 I/O 缓冲区一行后才进行实际的 I/O 操作;
- 当输入或输出中遇到换行符时,自动执行行缓冲操作;
- 如果文件流涉及到终端设备,则它们是行缓冲;否则是全缓冲;
- 不带缓冲: 对字符进行缓冲存储,即有一个字符操作就马上进行读写操作;
- 例如,如果使用
fputs
写入 15 个字符到不带缓冲的流中,会调用系统函数write
15 次; - 标准出错流
stderr
通常是不带缓冲的;
- 例如,如果使用
- 我们可以通过以下方式更改缓冲类型:
void setbuf(FILE *restrict_fp, char *restrict_buf);
int setvbuf(FILE *restrict_fp, char *restrict_buf, int mode, size_t size);
举个例子来说明:如果文件流涉及到终端设备,则它们是行缓冲;否则是全缓冲;代码如下:
// 文件名:file1.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int global = 4;
int main(void)
{
pid_t pid;
int vari = 5;
printf("%s: %d: before fork\n", __FILE__, __LINE__);
if((pid = fork()) < 0) {
printf("%s: %d: fork error\n", __FILE__, __LINE__);
exit(0);
}
else if(pid == 0) {
global++;
vari--;
printf("%s: %d: Child changed\n", __FILE__, __LINE__);
}
else printf("%s: %d: Parent did not changed\n", __FILE__, __LINE__);
printf("%s: %d: global = %d; vari = %d\n", __FILE__, __LINE__, global, vari);
return 0;
}
默认输出到终端,应该是行缓冲:
$ gcc file1.c -o file1
$ ./file1
file1.c: 13: before fork
file1.c: 24: Parent did not changed
file1.c: 26: global = 4; vari = 5
file1.c: 22: Child changed
file1.c: 26: global = 5; vari = 4
由上可知,file1.c: 13: before fork
只打印出了一行,标准输出是行缓冲,很快被新的一行冲掉了;
我们重定向输出到指定的文件,此时应该是全缓冲:
$ cat temp
file1.c: 13: before fork
file1.c: 24: Parent did not changed
file1.c: 26: global = 4; vari = 5
file1.c: 13: before forl
file1.c: 22: Child changed
file1.c: 26: global = 5; vari = 4
由上可知,file1.c: 13: before fork
打印了两行;