1. 程式人生 > >sync,fsync,fdatasync,fflush區別與聯系(轉載)

sync,fsync,fdatasync,fflush區別與聯系(轉載)

fread 特征 include 完全 通過 訪問 需要 應用 信息

前言:

Linux,unix在內核中設有 緩沖區高速緩沖或頁面高速緩沖,大多數磁盤I/O都通過緩沖進行,采用延遲寫技術。
sync:將所有修改過的快緩存區排入寫隊列,然後返回,並不等待實際寫磁盤操作結束
fsync:只對有文件描述符制定的單一文件起作用,並且等待些磁盤操作結束,然後返回。
fdatasync:類似fsync,但它只影響文件的數據部分。fsync還會同步更新文件的屬性。
fflush:標準I/O函數(如:fread,fwrite)會在內存建立緩沖,該函數刷新內存緩沖,將內容寫入內核緩沖,要想將其寫入磁盤,還需要調用fsync。(先調用fflush後調用fsync,否則不起作用)。

前面介紹函數write()時,我們認為該函數一旦返回,數據便已經寫到了文件中。但是這種概念只是宏觀上的。實際上,操作系統實現某些文件I/O時(如磁盤文件),為了保證I/O的效率,在內核通常會用到一片專門的區域(內存或獨立的I/O地址空間)作為I/O數據緩沖區。應用程序可以將這片內核區域看成是I/O數據的一個快速中轉站(圖3-5)。當調用write()函數寫出數據時,數據一旦寫到該緩沖區,函數便立即返回。此時寫出的數據可以用read()讀回,也可以被其他進程讀到,但是並不意味著它們已經被寫到了外部永久存儲介質上,即使調用close()關閉文件後也可能如此。內核I/O數據緩沖區中的數據只在適當的時候才由操作系統啟動外設進行傳輸,真正的傳輸動作由獨立於CPU的外設控制器或者外設本身(Linux稱之為DMA引擎)來完成。因此,從數據被實際寫到磁盤的角度來看,用write()寫出的文件數據與外部存儲設備並不是完全同步的。在現代計算機系統中,這種不同步的時間間隔非常短,一般只有幾秒或十幾秒,具體取決於寫出的數據量和I/O數據緩沖區的狀態。盡管不同步的時間間隔很短,但是如果在此期間發生掉電或者系統崩潰,則會導致所寫數據來不及寫至磁盤而丟失的情況。

由於現代計算機通常都十分穩定可靠,出現掉電或系統崩潰的情況極少,因此多數應用在寫文件時可以忽略這種瞬間不同步情況。但是,有些應用存在著這樣的一些同步點,在這些點上所寫的數據非常關鍵,或者必須及時保證文件的一致性。為了防備萬一,這些應用需要確保所有寫出的數據都已經傳送到了外部永久存儲介質上。為此,UNIX提供了兩種手段來實現這一目的。其中一種方法是對文件設置O_SYNC標誌(表3-1),這樣可以保證每次寫數據都直接寫到磁盤。如果設置了這個標誌,write()調用將直到數據已安全地寫到磁盤後(而不僅僅是系統的I/O緩沖區)才返回。但是這樣每次寫數據都保持同步的效率比較低。

技術分享圖片

另一種方法是只在需要時調用函數fsync()或者fdatasync()。
#include <unistd.h>
int fsync(int fildes);
int fdatasync(int fildes)

fsync()強制與描述字fildes相連文件的所有修改過的數據(包括核內I/O緩沖區中的數據)傳送到外部永久介質,即刷新fildes給出的文件的所有信息。調用 fsync()的進程將阻塞直到設備報告傳送已經完成。這裏“所有修改過的數據”包括用戶寫出的數據以及文件本身的特征數據(4.1.1節和表4-1),如文件的訪問時間、修改時間、文件的屬主等。

fdatasync()的功能與fsync()類似,只是它只強制傳送用戶已寫出的數據至物理存儲設備,不包括文件本身的特征數據。這樣可以適當減少文件刷新時的數據傳送量。不過有的系統並不支持fdatasync(),在這種系統上,fdatasync()等價於fsync()。

一個程序在寫出數據之後,如果繼續進行後續處理之前要求確保所寫數據已寫到磁盤,則應當調用fsync()。例如,數據庫應用通常會在調用write()保存關鍵交易數據的同時也調用fsync()。

我們在2.7節曾討論了標準I/O流緩沖區的問題以及函數fflush()。那麽,這兩個緩沖區有何不同?回答是,內核I/O緩沖區是由操作系統管理的空間,而流緩沖區是由標準I/O庫管理的用戶空間。fflush()只刷新位於用戶空間中的流緩沖區。fflush()返回後,只保證數據已不在流緩沖區中,並不保證它們一定被寫到了磁盤。此時,從流緩沖區刷新的數據可能已被寫至磁盤,也可能還待在內核I/O緩沖區中。要確保流I/O寫出的數據已寫至磁盤,那麽在調用fflush()後還應當調用fsync()。

sync,fsync,fdatasync,fflush區別與聯系(轉載)