unbuffered low level IO 和 bufferd IO

  在常见的IO函数中有这样的一些系列,open, read, write, lseek及close。这些IO函数经常被称为不带缓冲的I/O(unbuffered I/O),不带缓冲的是什么意思呢?术语不带缓冲指的是每个read和write都调用了内核的一个系统调用。这些函数在调用的时候系统调用直接进行了磁盘文件的写入操作。那么你会发现如果我的程序出现这样的需求,有很多个连续的对同一个文件进行I/O的操作,你的程序将会不断地进行磁盘操作,这将会是一件很可怕的事情,程序运行的会异常的慢,怎么解决呢?很简单,缓冲呗,我想缓冲这个名词在计算机的世界里你不陌生吧?

  所谓的缓冲是指在你对文件进行读取或者改写的时候,系统会为你申请一块内存空间,之后的所有操作都是在此内存空间上面进行操作,当你对该文件的操作结束的时候,或者关闭该文件的句柄的时候,或者你有意刷新缓冲区的时候,系统会将缓冲区的内容一并写至磁盘。这样对比一下之前的unbufferd I/O,磁盘操作相比内存操作要慢得多(你应该知道吧?),所以也称之为高级I/O。那么你可能会问,带缓冲的IO API有哪些呢?罗列一下常见的大概有这些:fopen, fread, fwrite, fclose。这些是标准I/O,也就是在<stdio.h>中声明的API,而上面的那些open...这些是在<unistd.h>下声明的。这下你应该知道STDIN和STDIN_FILENO的区别了吧。层次不一样嘛,一个是unbuffered的,一个是buffered的。(低级与高级的)由于不带缓冲的I/O函数已经不是ISO C的组成部分,所以不建议使用该类函数。

  下面是一个有意思的程序,用于测试缓冲I/O和非缓冲I/O的函数区别的。

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
	int a=8;
	int b=1;
	char p_str[]={"write to stdout\n"};
	pid_t pid;
	write(STDOUT_FILENO,p_str,sizeof(p_str)-1);
       printf("before fork!\n");
//	fflush(stdout);	
	if(pid=fork()==0){
		a++;
		b++;
	}else{
		sleep(2);	
	}
	printf("pid %d :a = %d; b = %d\n",getpid(),a,b);
	return 0;
}

在本机器上直接编译运行

输出如下:

write to stdout

before fork!

pid 22040: a=9;b=2

pid 22039: a=9;b=1

如果我将程序的输出重定向到另一个临时文件的话,结果的输入又将如下:

write to stdout

before fork!

pid 22045: a=9;b=2

before fork!

pid 22044: a=8;b=1

解释如下:

1 write是unbuffered,所以在执行fork时,已经输出到stdout中了。

直接执行时,stdout和interactive terminal相连接,所以是line buffered。Printf执行后,就被输出到stdout中了。因为字符串以换行符结束。

输出重定向执行时,stdout被重定向为文件temp.out。所以是fully bufferedPrintf执行后,并没有输出到stdout中。后面执行了fork,输出缓冲区也被拷贝到了child中。在parentchild中,再执行printf时,实际是向输出缓冲区追加内容。当parentchild结束时,输出缓冲区的内容被flush

至于如何将测试二的输出和测试一的结果一样,我想你应该能够想的到。

这让我想起来陈皓老师的一篇文章大家可以参考一下,一道面试题哟。http://coolshell.cn/articles/7965.html

posted @ 2012-09-09 23:29  f_x_p  阅读(511)  评论(0编辑  收藏  举报