linux文件IO与内存映射:用户空间的IO缓冲区
文章目錄
- 用戶空間IO緩沖區(qū)產(chǎn)生
- IO緩沖區(qū) 描述
- IO緩沖區(qū)的寫模式
- 自定義IO緩沖區(qū)
用戶空間IO緩沖區(qū)產(chǎn)生
系統(tǒng)調(diào)用過程中會產(chǎn)生的開銷如下:
- 切換CPU到內(nèi)核態(tài)
- 進行數(shù)據(jù)內(nèi)容的拷貝,從用戶態(tài)到內(nèi)核態(tài)或者從內(nèi)核態(tài)到用戶態(tài)
- 切換CPU到用戶態(tài)
以上為普通到系統(tǒng)調(diào)用過程中操作系統(tǒng)需要產(chǎn)生的額外開銷,為了提升系統(tǒng)調(diào)用的性能,這里推出用戶空間的IO緩沖區(qū),即文件讀寫在用戶空間時寫入IO緩沖區(qū),后續(xù)的寫入或者讀出page cache則直接由IO緩沖區(qū)進行讀寫。
IO緩沖區(qū)所處操作系統(tǒng)位置如下圖:
IO緩沖區(qū) 描述
C標準庫創(chuàng)建的IO緩沖區(qū)
- 在用戶空間,為每個打開的文件分配一個I/O緩沖區(qū)、分配一個文件描述符、I/O緩沖區(qū)信息和文件描述符一起封裝在FIFE結(jié)構(gòu)體中
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);
關(guān)于FILE結(jié)構(gòu)體的內(nèi)容如下/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
};
其中重要的數(shù)據(jù)結(jié)構(gòu)為:
int _fileno;我們的文件描述符char *_IO_buf_base;IO緩沖區(qū)的起始區(qū)域char *_IO_buf_end;IO緩沖區(qū)的結(jié)束區(qū)域
當使用fread進行讀文件時
- 打開文件,獲取到文件描述符
_fileno - 利用文件描述符獲取到文件inode,根據(jù)文件inode先到io緩沖區(qū)中獲取當前文件內(nèi)容,如果獲取不到則執(zhí)行下一步,否則直接返回。
- 根據(jù)文件
inode從page cache中獲取到對應(yīng)的緩存頁的內(nèi)容 - 將獲取到的內(nèi)容讀到讀的IO緩沖區(qū)
當使用fwrite寫文件時
- 打開文件,獲取到文件描述符
- 利用文件描述符獲取到文件inode,將需要寫到內(nèi)容寫入到io緩沖區(qū)中
- io緩沖區(qū)利用fflush將其中到內(nèi)容寫入到page cache頁高速緩沖區(qū)中
- 再由page cache根據(jù)是否達到閾值,將page cache中的數(shù)據(jù)pdflush回寫到磁盤中
IO緩沖區(qū)的寫模式
使用fwrite寫文件時的第二步 IO 緩沖區(qū)中的數(shù)據(jù)fflush到page cache時有幾種不同的寫模式,即根據(jù)不同的模式將IO緩沖區(qū)的數(shù)據(jù)寫入到page cache中。
- 塊緩沖(block buffered):
固定字節(jié)的緩沖區(qū)大小,比如跟文件相關(guān)的流都是塊緩沖
標準IO塊緩沖為完全緩沖(full bufferring)
此時,當客戶端將塊緩沖區(qū)寫滿之后,才會向page cache中下刷數(shù)據(jù),一般的文件操作都為塊緩沖區(qū) - 行緩沖(line buffered):
遇到換行符,緩沖區(qū)中的數(shù)據(jù)會拷貝到內(nèi)核緩沖區(qū) - 無緩沖(unbuffered)
數(shù)據(jù)直接拷貝到內(nèi)核緩沖區(qū)
如:標準錯誤stderr采用無緩沖模式
自定義IO緩沖區(qū)
系統(tǒng)默認開辟的IO緩沖區(qū)大小為8K,但是很多時候我們需要寫入文件內(nèi)容是大于8K,這個時候需要我們自定義IO緩沖區(qū)大小,使用如下C庫函數(shù):
- 頭文件
<stdio.h> - 函數(shù)使用:
void setbuf(FILE *stream, char *buf); //無緩沖區(qū) void setbuffer(FILE *stream, char *buf, size_t size);//塊緩沖區(qū) void setlinebuf(FILE *stream);//行緩沖區(qū)//兼容三種緩沖期 int setvbuf(FILE *stream, char *buf, int mode, size_t size); - 參數(shù)描述:
stream指向流的指針buf緩沖區(qū)地址mode緩沖區(qū)類型
如下三種_IONBF //無unbuffered _IOLBF //行l(wèi)ine buffered _IOFBF //塊fully bufferedsize緩沖區(qū)內(nèi)字節(jié)數(shù)
代碼如下:
#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;
}
總結(jié)
以上是生活随笔為你收集整理的linux文件IO与内存映射:用户空间的IO缓冲区的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 绝对性不孕症
- 下一篇: linux文件IO与内存映射:分散/聚集