同步內核緩沖區 sync、fsync和fdatasync函數


同步內核緩沖區

1.緩沖區簡單介紹

    人生三大錯覺之中的一個:在調用函數write()時,我們覺得該函數一旦返回,數據便已經寫到了文件里.可是這樣的概念僅僅是宏觀上的.實際上。操作系統實現某些文件I/O時(如磁盤文件)。為了保證I/O的效率,在內核一般會用到一片專門的區域(內存或獨立的I/O地址空間)作為I/O數據緩沖區.它用在輸入輸出設備和CPU之間,用來緩存數據,使得低速的設備和快速的CPU可以協調工作避免低速的輸入輸出設備長時間占用CPU。降低系統調用,提高了CPU的工作效率.

2.不同步的write()

    傳統的UNIX或LINUX系統在設計時使用了內核緩沖區,設有快速緩沖區或頁面快速緩沖區,大多數磁盤I/O都通過緩沖區進行.當將數據寫入文件時,內核通常先將該數據拷貝到當中一個緩沖區。假設該緩沖區尚未寫滿。則並不將其排入輸出隊列,而是等待其寫滿或者當內核須要重用該緩沖區以便存放其它磁盤塊數據時,再將該緩沖區排入輸出隊列;然后待其到達隊首時。才進行實際的I/O操作.這樣的輸出方式被稱為延遲寫.
    當調用write()函數寫出數據時,數據一旦寫到該緩沖區(關鍵:僅僅是寫到緩沖區),函數便馬上返回.此時寫出的數據能夠用read()讀回,也能夠被其它進程讀到,可是並不意味着它們已經被寫到了外部永久存儲介質上。即使調用close()關閉文件后也可能如此. 由於緩沖區的數據可能還在等待輸出.
    因此。從數據被實際寫到磁盤的角度來看。用write()寫出的文件數據與外部存儲設備並非全然同步的.不同步的時間間隔非常短,一般僅僅有幾秒或十幾秒,詳細取決於寫出的數據量和I/O數據緩沖區的狀態.雖然不同步的時間間隔非常短,可是假設在此期間發生掉電或者系統崩潰,則會導致所寫數據來不及寫至磁盤而丟失的情況.
    注意:內核將緩沖區中的數據“寫”到標准輸入磁盤文件里,這里“寫”不是將緩沖區中的數據移動到磁盤文件里,而是復制到磁盤文件里,也就說此時磁盤文件里還保留一份緩沖區內容的備份.如圖1所看到的.做出這一設計也是有其道理的。假設寫出到磁盤文件上,磁盤壞了或滿了等等,總之就是無法將數據送出,假如沒備份。那數據不是丟掉了.也就是說內核會等待寫入磁盤動作完畢后,才放心的將備份的數據刪除掉.在下文討論的三個函數中也將涉及到這個過程.
 
圖1 數據傳入過程示意圖

    為了保證磁盤上實際文件系統與緩沖區快速緩存中內容的一致性,UNIX系統提供了sync、fsync和fdatasync三個函數.

3.sync函數

頭文件:#include<unistd.h>
定義函數:void sync(void);
返回值:若成功則返回0,若出錯則返回-1。同一時候設置errno以指明錯誤.
函數說明:
    sync負責將系統緩沖區的數據“寫入”磁盤。以確保數據的一致性和同步性.注意:sync函數僅僅是將全部改動過的塊緩沖區排入寫隊列,然后就返回。他並不等待實際I/O操作結束.所以不要覺得調用了sync函數,就覺得數據已安全的送到磁盤文件上,有可能會出現故障,可是sync函數是無法得知的.
    系統守候進程一般每隔一段時間調用一次sync函數,確保定期刷新內核的塊緩存.UNIX系統中,系統守候進程update會周期性地(一般每一個30秒)調用sync函數.命令sync(1)也調用sync函數.

4.fsync函數

頭文件:#include<unistd.h>
定義函數:int fsync(int filedes);
返回值:若成功則返回0。若出錯則返回-1。同一時候設置errno以指明錯誤.
函數說明:
    與sync函數不同,fsync函數僅僅對由文件描符filedes指定的單一文件起作用,強制與描寫敘述字fildes相連文件的全部改動過的數據(包含核內I/O緩沖區中的數據)傳送到外部永久介質。即刷新fildes給出的文件的全部信息。而且等待寫磁盤操作結束,然后返回.調用 fsync()的進程將堵塞直到設備報告傳送已經完畢.這個fsync就安全點了.
    一個程序在寫出數據之后。假設繼續進行興許處理之前要求確保所寫數據已寫到磁盤,則應當調用fsync().比如,數據庫應用一般會在調用write()保存關鍵交易數據的同一時候也調用fsync().這樣更能保證數據的安全可靠.

5.fdatasync函數

頭文件:#include<unistd.h>
定義函數:int fdatasync(int filedes);
返回值:若成功則返回0。若出錯則返回-1,同一時候設置errno以指明錯誤.
函數說明:
    fdatasync函數類似於fsync函數,但它僅僅影響文件數據部分。強制傳送用戶已寫出的數據至物理存儲設備。不包含文件本身的特征數據.這樣能夠適當降低文件刷新時的數據傳送量.而除數據外,fdatasync還會同步更新文件的屬性.

6.錯誤代碼

EBADF:文件描寫敘述符無效。或文件已關閉.
EIO : 讀寫的過程中錯誤發生 .
EROFSEINVAL:文件所在的文件系統不支持同步.

7.fflush()與fsync()的聯系

    內核I/O緩沖區是由操作系統管理的空間,而流緩沖區是由標准I/O庫管理的用戶空間.fflush()僅僅刷新位於用戶空間中的流緩沖區.fflush()返回后。僅僅保證數據已不在流緩沖區中,並不保證它們一定被寫到了磁盤.此時。從流緩沖區刷新的數據可能已被寫至磁盤。也可能還待在內核I/O緩沖區中.要確保流I/O寫出的數據已寫至磁盤,那么在調用fflush()后還應當調用fsync().

8.綜述

    盡管延遲寫降低了磁盤讀寫次數,可是卻降低了文件內容的更新速度,使得欲寫到文件里數據在一段時間內並沒有寫到磁盤上。當系統發生問題時,這樣的延遲可能造成文件更新內容的丟失。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM