ソフトウェアエンジニア現役続行

雑多なことを綴ります

fflushとfsyncとfdatasync

どれもバッファリングされているデータをフラッシュする関数ですが、それぞれの違いを再確認しました。

int fflush(FILE *stream);
Cライブラリが与えているユーザー空間のバッファしかフラッシュしない。データが物理的にディスクに保存されることを保証したければ、fsync(2)などでカーネルバッファもフラッシュしなければならない。

int fsync(int fd);
fdで参照されているファイルのキャッシュ(カーネル内のバッファ)をディスクデバイスにフラッシュする。この呼び出しはフラッシュが終わったとデバイスが報告するまでブロックする。

int fdatasync(int fd);
fsync()と同様だが、fdatasync()は、それ以降のデータ読み込みを正しく扱うためにメタデータ(たとえばst_atime や st_mtime)が必要にならない限り、変更されたメタデータをフラッシュしない。fdatasync()の狙いは、全てのメタデータをディスクと同期する必要のないアプリケーションに対して、ディスクアクセスを減らすことである


これらを踏まえると、Cライブラリ(fputsなど)を使って書き込んだデータを効率的かつ確実にディスクに保存するには、fflush(3)を呼んで、かつfdatasync(2)を呼ぶのが良さそうです。

以下がサンプルソースです。エラー処理は省いています。


/* 第1引数で与えられたファイルに、
* 第2引数で与えられた文字を書き込むプログラム */
int main(int argc, char **argv)
{
FILE *writer = fopen(argv[1], "w");
int fd = fileno(writer);

// データを書き込み
fputs(argv[2], writer);
fputc('\n', writer);

// Cライブラリが与えているユーザー空間のバッファをフラッシュ
fflush(writer);

// fdで参照しているファイルのキャッシュをディスクにフラッシュ
fdatasync(fd);

// fcloseでファイルをクローズ。close(fd)まで呼ぶ必要はない
fclose(writer);

return 0;
}