文章目录
用户空间IO缓冲区产生IO缓冲区 描述IO缓冲区的写模式自定义IO缓冲区用户空间IO缓冲区产生
系统调用过程中会产生的开销如下:
切换CPU到内核态进行数据内容的拷贝,从用户态到内核态或者从内核态到用户态切换CPU到用户态
以上为普通到系统调用过程中操作系统需要产生的额外开销,为了提升系统调用的性能,这里推出用户空间的IO缓冲区,即文件读写在用户空间时写入IO缓冲区,后续的写入或者读出page cache则直接由IO缓冲区进行读写。
IO缓冲区所处操作系统位置如下图:
IO缓冲区 描述
C标准库创建的IO缓冲区
在用户空间,为每个打开的文件分配一个I/O缓冲区、分配一个文件描述符、I/O缓冲区信息和文件描述符一起封装在FIFE结构体中size_t fread(void *ptr,size_t size,size_t memb,FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
关于FILE结构体的内容如下/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h
:
/* The tag name of this struct is _IO_FILE to preserve historicC++ mangled names for functions taking FILE* arguments.That name should not be used in new code. */struct _IO_FILE{int _flags;/* High-order word is _IO_MAGIC; rest is flags. *//* The following pointers correspond to the C++ streambuf protocol. */char *_IO_read_ptr;/* Current read pointer */char *_IO_read_end;/* End of get area. */char *_IO_read_base;/* Start of putback+get area. */char *_IO_write_base;/* Start of put area. */char *_IO_write_ptr;/* Current put pointer. */char *_IO_write_end;/* End of put area. */char *_IO_buf_base;/* Start of reserve area. */char *_IO_buf_end;/* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base; /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno;int _flags2;__off_t _old_offset; /* This used to be _offset but it's too small. *//* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;signed char _vtable_offset;char _shortbuf[1];_IO_lock_t *_lock;#ifdef _IO_USE_OLD_IO_FILE};
其中重要的数据结构为:
int _fileno;
我们的文件描述符char *_IO_buf_base;
IO缓冲区的起始区域char *_IO_buf_end;
IO缓冲区的结束区域
当使用fread进行读文件时
打开文件,获取到文件描述符_fileno
利用文件描述符获取到文件inode,根据文件inode先到io缓冲区中获取当前文件内容,如果获取不到则执行下一步,否则直接返回。根据文件inode
从page cache中获取到对应的缓存页的内容将获取到的内容读到读的IO缓冲区
当使用fwrite写文件时
打开文件,获取到文件描述符利用文件描述符获取到文件inode,将需要写到内容写入到io缓冲区中io缓冲区利用fflush将其中到内容写入到page cache页高速缓冲区中再由page cache根据是否达到阈值,将page cache中的数据pdflush回写到磁盘中
IO缓冲区的写模式
使用fwrite写文件时的第二步 IO 缓冲区中的数据fflush到page cache时有几种不同的写模式,即根据不同的模式将IO缓冲区的数据写入到page cache中。
块缓冲(block buffered):
固定字节的缓冲区大小,比如跟文件相关的流都是块缓冲
标准IO块缓冲为完全缓冲(full bufferring)
此时,当客户端将块缓冲区写满之后,才会向page cache中下刷数据,一般的文件操作都为块缓冲区行缓冲(line buffered):
遇到换行符,缓冲区中的数据会拷贝到内核缓冲区无缓冲(unbuffered)
数据直接拷贝到内核缓冲区
如:标准错误stderr采用无缓冲模式
自定义IO缓冲区
系统默认开辟的IO缓冲区大小为8K,但是很多时候我们需要写入文件内容是大于8K,这个时候需要我们自定义IO缓冲区大小,使用如下C库函数:
头文件<stdio.h>
函数使用:
void setbuf(FILE *stream, char *buf); //无缓冲区void setbuffer(FILE *stream, char *buf, size_t size);//块缓冲区void setlinebuf(FILE *stream);//行缓冲区//兼容三种缓冲期int setvbuf(FILE *stream, char *buf, int mode, size_t size);
参数描述:stream
指向流的指针buf
缓冲区地址mode
缓冲区类型
如下三种
_IONBF //无unbuffered_IOLBF //行line buffered_IOFBF //块fully buffered
size
缓冲区内字节数
代码如下:
#include <stdio.h>int main() {char buf[BUFSIZ];char buf2[BUFSIZ];//printf("BUFSIZ is %d\n",BUFSIZ);setvbuf(stdout,buf,_IOFBF,BUFSIZ);printf("BUFSIZ after setvbuf is %d\n",BUFSIZ);setbuffer(stdout, buf2,10240);printf("hello world\n");printf("buf:%s\n",buf);printf("buf2:%s\n",buf2);return 0;}
如果觉得《linux文件IO与内存映射:用户空间的IO缓冲区》对你有帮助,请点赞、收藏,并留下你的观点哦!