简体   繁体   English

fflush和fsync之间的区别

[英]Difference between fflush and fsync

I thought fsync() does fflush() internally, so using fsync() on a stream is OK. 我认为fsync()在内部执行fflush() ,因此在流上使用fsync()是可以的。 But I am getting an unexpected result when executed under network I/O. 但是在网络I / O下执行时,我得到了意想不到的结果。

My code snippet: 我的代码片段:

FILE* fp = fopen(file, "wb");
/* multiple fputs() calls like: */
fputs(buf, fp);
...
...
fputs(buf.c_str(), fp);
/* get fd of the FILE pointer */
fd = fileno(fp);
#ifndef WIN32
ret = fsync(fd);
#else
ret = _commit(fd);
fclose(fp);

But it seems _commit() is not flushing the data (I tried on Windows and the data was written on a Linux exported filesystem). 但似乎_commit()并没有刷新数据(我在Windows上试过并且数据是在Linux导出的文件系统上编写的)。

When I changed the code to be: 当我将代码更改为:

FILE* fp = fopen(file, "wb");
/* multiple fputs() calls like: */
fputs(buf, fp);   
...   
...
fputs(buf.c_str(), fp);
/* fflush the data */
fflush(fp);
fclose(fp);

it flushes the data. 它会刷新数据。

I am wondering if _commit() does the same thing as fflush() . 我想知道_commit()是否与fflush()做同样的事情。 Any inputs? 有什么投入?

fflush() works on FILE* , it just flushes the internal buffers in the FILE* of your application out to the OS. fflush()适用于FILE* ,它只是将应用程序的FILE*中的内部缓冲区刷新到OS。

fsync works on a lower level, it tells the OS to flush its buffers to the physical media. fsync在较低级别工作,它告诉操作系统将其缓冲区刷新到物理介质。

OSs heavily cache data you write to a file. 操作系统会大量缓存您写入文件的数据。 If the OS enforced every write to hit the drive, things would be very slow. 如果操作系统强制每次写入命中驱动器,事情就会非常缓慢。 fsync (among other things) allows you to control when the data should hit the drive. fsync (除其他外)允许您控制数据何时应该到达驱动器。

Furthermore, fsync/commit works on a file descriptor. 此外,fsync / commit适用于文件描述符。 It has no knowledge of a FILE* and can't flush its buffers. 它不知道FILE*并且无法刷新其缓冲区。 FILE* lives in your application, file descriptors live in the OS kernel, typically. FILE*通常存在于您的应用程序中,文件描述符通常位于OS内核中。

The standard C function fflush() and the POSIX system call fsync() are conceptually somewhat similar. 标准C函数fflush()和POSIX系统调用fsync()在概念上有些类似。 fflush() operates on C file streams ( FILE objects), and is therefore portable. fflush()对C文件流( FILE对象)进行操作,因此是可移植的。 fsync() operate on POSIX file descriptors. fsync()对POSIX文件描述符进行操作。 Both cause buffered data to be sent to a destination. 两者都会导致缓冲数据被发送到目的地。

On a POSIX system, each C file stream has an associated file descriptor , and all the operations on a C file stream will be implemented by delegating, when necessary, to POSIX system calls that operate on the file descriptor. 在POSIX系统上,每个C文件流都有一个关联的文件描述符 ,并且必要时,通过委托对文件描述符进行操作的POSIX系统调用来实现C文件流上的所有操作。

One might think that a call to fflush on a POSIX system would cause a write of any data in the buffer of the file stream, followed by a call of fsync() for the file descriptor of that file stream. 有人可能会认为在POSIX系统上调用fflush会导致在文件流缓冲区中write任何数据,然后调用fsync()来获取该文件流的文件描述符。 So on a POSIX system there would be no need to follow a call to fflush with a call to fsync(fileno(fp)) . 所以在POSIX系统上,没有必要通过调用fsync(fileno(fp))跟随fflush的调用。 But is that the case: is there a call to fsync from fflush ? 但情况是这样的:是否有来自fflush fsync

No, calling fflush on a POSIX system does not imply that fsync will be called. 不,在POSIX系统上调用fflush并不意味着将fsync

The C standard for fflush says (emphasis added) it fflush的C标准说(重点补充)它

causes any unwritten data for [the] stream to be delivered to the host environment to be written to the file 导致[流]的任何未写入数据被传递到主机环境以写入文件

Saying that the data is to be written, rather than that is is written implies that further buffering by the host environment is permitted. 说的数据是要被写入,而不是是写入意味着由主机环境进一步缓冲是允许的。 That buffering by the "host environment" could include, for a POSIX environment, the internal buffering that fsync flushes. 对于POSIX环境,“主机环境”的缓冲可以包括fsync刷新的内部缓冲。 So a close reading of the C standard suggests that the standard does not require the POSIX implementation to call fsync . 因此仔细阅读C标准表明该标准不要求POSIX实现调用fsync

The POSIX standard description of fflush does not declare, as an extension of the C semantics , that fsync is called. 作为C语义扩展 fflushPOSIX标准描述并未声明fsync

I could say that for simplicity: 为简单起见我可以说:

use fsync() with not streaming files (integer file descriptors) 使用fsync()而不是流文件(整数文件描述符)

use fflush() with file streams. fflush()与文件流一起使用。

Also here is the help from man: 这里还有人的帮助:

int fflush(FILE *stream); // flush a stream, FILE* type

int fsync(int fd); // synchronize a file's in-core state with storage device
                    // int type

To force the commitment of recent changes to disk, use the sync() or fsync() functions. 要强制最近更改磁盘,请使用sync()或fsync()函数。

fsync() will synchronize all of the given file's data and metadata with the permanent storage device. fsync()将使永久存储设备同步所有给定文件的数据和元数据。 It should be called just before the corresponding file has been closed. 它应该在相应文件关闭之前调用。

sync() will commit all modified files to disk. sync()会将所有已修改的文件提交到磁盘。

I think below document from python ( https://docs.python.org/2/library/os.html ) clarifies it very well. 我认为python( https://docs.python.org/2/library/os.html )下面的文档很清楚地说明了这一点。

os.fsync(fd) Force write of file with filedescriptor fd to disk. os.fsync(fd)强制将filedescriptor fd写入磁盘。 On Unix, this calls the native fsync() function; 在Unix上,这会调用本机fsync()函数; on Windows, the MS _commit() function. 在Windows上,MS _commit()函数。

If you're starting with a Python file object f, first do f.flush(), and then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk. 如果您从Python文件对象f开始,首先执行f.flush(),然后执行os.fsync(f.fileno()),以确保将与f关联的所有内部缓冲区写入磁盘。

Availability: Unix, and Windows starting in 2.2.3. 可用性:Unix和Windows从2.2.3开始。

fflush() and fsync() can be used to try and ensure data is written to the storage media (but it is not always be possible): fflush()fsync()可用于尝试确保将数据写入存储介质(但并非总是可行):

  1. first use fflush(fp) on the output stream ( fp being a FILE * obtained from fopen or one of the standard streams stdout or stderr ) to write the contents of the buffer associated with the stream to the OS. 首先在输出流上使用fflush(fp)fp是从fopen或其中一个标准流stdoutstderr获得的FILE * ),以将与流关联的缓冲区的内容写入OS。
  2. then use fsync(fileno(fp)) to tell the OS to write its own buffers to the storage media. 然后使用fsync(fileno(fp))告诉操作系统将自己的缓冲区写入存储介质。

Note however that fileno() and fsync() are POSIX functions that might not be available on all systems, notably Microsoft legacy systems where alternatives may be named _fileno() , _fsync() or _commit() ... 但请注意, fileno()fsync()是可能并非在所有系统上都可用的POSIX函数,特别是Microsoft遗留系统,其中备选方案可以命名为_fileno()_fsync()_commit() ......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM