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

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

前言:

        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緩衝區)才返回。但是這樣每次寫資料都保持同步的效率比較低。

bubuko.com,布布扣
 

另一種方法是隻在需要時呼叫函式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()。