本文重點說明下面內容:
- 什么是標準IO,什么是檔案IO?
- 什么是Direct IO? O_SYNC標識有什么意義?
- 各個層面的快取如何同步?
- 還在page cache中的臟頁可以讀寫嗎?
IO路徑上的各層buff
Application buff
|
clib buff
|
page cache
|
disk cache
標準IO
- 標準IO操作的是流(File物件)
- 標準IO可以設定快取,這個快取是用戶態buffer,一般稱為clib buff
api
#include <stdio.h>
//打開流
FILE *fopen(const char *pathname, const char *type);
//關閉流
int fclose(File *fp);
// 重繪流
int fflush(FILE *fp);
// 一次讀寫一個字符
int fgetc(FILE *fp);
int fputc(FILE *fp);
// 一次讀寫一行
char* fgets(char* buf, int n, FILE* fp);
int fputs(const char *str, FILE* fp);
// 二進制讀寫
size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp);
// 格式化輸入輸出
int fprintf(FILE *fp, const char* format, ...);
int fscanf(FILE *fp, const char *format, ...);
// 示例
#include <stdio.h>
#include <stdlib.h>
int main(void){
char buf[1024];
while (fgets(buf, 1024, stdin) != NULL)
if (fputs(buf, stdout) == EOF)
printf("output error");
if (ferror(stdin))
printf("input error");
exit(0);
}
說明
- 呼叫fwrite, fputc, fputs系列函式后,資料被保存到clib buf中,依然處于用戶態,如果此時應用行程crash掉,這些資料將丟失,
- 在呼叫fflush可將clib buf中的資料寫入內核的page cache中,
- 呼叫fclose也會將clib buff中的資料重繪到內核,并且把clib buff中的輸入資料丟棄,
- clib buf被寫滿時也會呼叫系統呼叫
從這些標準IO的API可看出,標準IO比檔案IO要簡潔很多,沒有各種標識,沒有sync, nonblock等,
上列API具體使用細節可參考《unix環境高級編程》第5章,
檔案IO
檔案IO是直接操作linux系統呼叫,大部分的問題都是使用檔案IO帶來的,
api
int open(const char *pathname, int oflag);
int close(int filedes);
ssize_t read(int filedes, void* buff, size_t nbytes);
ssize_t write(int filedes, const void* buff, size_t nbytes);
int fsync(int filedes);
int fcntl(int filedes, int cmd);
int ioctl(int filedes, int request);
說明
- O_SYNC標識打開的檔案,會在write系統呼叫時,會等待IO從底層回傳;O_SYNC僅對寫有意義,
- O_DIRECT標識打開的檔案不經過page cache; O_DIRECT對讀寫都是有意義的,
- O_NONBLOCK標識打開的檔案(一般是網路IO,終端設備IO) ,在不可讀寫時立即回傳EAGAIN等錯誤碼,
- O_SYNC, O_DIRECT有區別如下,
size_t wirte_file()
{
if(o_DIRECT)
direct_io();
else
buffered_io();
if( O_SYNC )
wait_data_synced();
}
sync是write through page cache,資料在記憶體中是有對應的鏡像的,direct是繞過了page cache
上述API細節可參考《unix環境高級編程》第3章,
mmap
api
#include <sys/mman.h>
void *mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
mmap在calling process的虛擬地址空間中創建一個映射,主要有以下兩種常用方式:
-
對檔案創建一個mapping,讀寫檔案可以用讀寫記憶體替代,
-
匿名映射,傳入的fd為-1
創建mapping后,省掉了資料從在用戶態buff和內核page cache的拷貝
后續整理下linux系統檔案IO流程
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/159448.html
標籤:Linux
