sync,fsync,fdatasync,fflush之间的区别 |
在 大多数的unix/linux对磁盘io的写操作都是通过缓存来完成的,基本的原理如下:当将数据写入文件时,内核通常先将该数据复制到其中一个缓冲区 中,如果该缓冲区尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要重用该缓冲区以便存放其他磁盘块数据时,再将该缓冲排入输出队列,然后 待其到达队首时,才进行实际的I/O操作。 我们称之为延迟写,极大的减少了写磁盘的次数。
但是在没写特殊的应用中我们需要实时的将应用层数据写入到磁盘上 特别是一些高可靠性要求的系统中 数据需要及时的写入磁盘 即便是瞬时系统故障 数据也可以安全恢复,于是就有了sync、fsync,fdatasync,fflush等函数。
主要区别: sync:将所有修改过的快缓冲区排入写队列然后返回,并不等待实际写磁盘操作结束; 通常称为update的系统守护进程会周期性地(一般每隔30秒)调用sync函数。这就保证了定期冲洗内核的块缓冲区。该函数没有参数,对系统中的所有缓冲区起作用。
fsync:只对有文件描述符指定的单一文件起作用,并且等待写磁盘操作结束,然后返回(因此最安全);该函数以指定的文件描述符(对应以open等函数打开的文件)为参数,仅对该描述符指定的文件起作用。
fdatasync:类似于fsync,但只影响文件的数据部分。而fsync还会同步更新文件的属性;实际上目前 glibc中fdatasync函数的实现已经和fsync一摸一样了。可以理解为与fsync相同
fflush:标准IO函数(如fread,fwrite等)会在内存中建立缓冲,该函数刷新内存缓冲,将内容写入内核缓冲,要想将其真正写入磁盘,还需要调用fsync。(即先调用fflush然后再调用fsync,否则不会起作用)。fflush以指定的文件流描述符为参数(对应以fopen等函数打开的文件流),仅仅是把上层缓冲区中的数据刷新到内核缓冲区就返回,因此相对于fsync而言不是很安全,还需要再调用一下fsync来把数据真正写入硬盘。
为了实现以上功能,需要把文件流描述符(fp)转换为文件描述符(fd),以方便fsync的调用,使用以下函数:
int fileno(FILE *fp); <- in stdio.
总结&#xff1a;
如果是对所有的缓冲区发出写硬盘的命令&#xff0c;应该使用sync函数&#xff0c;但应注意该函数仅仅只是把该命令放入队列就返回了&#xff0c;在编程时应注意这一点&#xff1b;
如果对要把一个已打开的文件所做的修改提交到硬盘&#xff0c;应调用fsync函数&#xff0c;该函数会在数据实际写入硬盘后才返回&#xff0c;因此是最安全最可靠的方式&#xff1b;
如果是针对一个已打开的文件流操作&#xff0c;则应首先调用fflush把修改同步到内核缓冲区&#xff0c;然后再调用fsync把修改实际的同步到硬盘。
本文转自http://windlazio.blogspot.com/2011/07/syncfsyncfdatasyncfflush.html。