15

I was reading the cplusplus.com tutorial on I/O. At the end, it says fstream buffers are synchronized with the file on disc

Explicitly, with manipulators: When certain manipulators are used on streams, an explicit synchronization takes place. These manipulators are: flush and endl.

and

Explicitly, with member function sync(): Calling stream's member function sync(), which takes no parameters, causes an immediate synchronization. This function returns an int value equal to -1 if the stream has no associated buffer or in case of failure. Otherwise (if the stream buffer was successfully synchronized) it returns 0.

in addition to a few other implicit cases ( such as destruction and stream.close() )

What is the difference between calling fstream::flush() and fstream::sync()? endl?

In my code, I've always used flush().

Documentation on std::flush():

Flush stream buffer

Synchronizes the buffer associated with the stream to its controlled output sequence. This effectively means that all unwritten characters in the buffer are written to its controlled output sequence as soon as possible ("flushed").

Documentation on std::streambuf::sync():

Synchronize input buffer with source of characters

It is called to synchronize the stream buffer with the controlled sequence (like the file in the case of file streams). The public member function pubsync calls this protected member function to perform this action.

Forgive me if this is a newbie question; I am a noob.

Community
  • 1
  • 1
cjcurrie
  • 624
  • 1
  • 4
  • 15

5 Answers5

17

basic_ostream::flush This is a non-virtual function which writes uncommited changes to the underlying buffer. In case of error, it sets an error flag in the used stream object. This is because the return value is a reference to the stream itself, to allow chaining.

basic_filebuf::sync This is a virtual function which writes all pending changes to the underlying file and returns an error code to signal success or failure.

endl This, when applied to an ostream, writes an '\n' to the stream and then calls flush on that stream.

So, essentially: flush is a more general function for any stream, whereas sync is explicitly bound to a file. flush is non-virtual, whereas sync is virtual. This changes how they can be used via pointers (to base class) in the case of inheritance. Furthermore, they differ in how they report errors.

Agentlien
  • 4,996
  • 1
  • 16
  • 27
  • 1
    Great answer. Could you confirm/clarify DWright and perreal's statements about flush() being handled by the kernel and sync() being handled by the library (when the kernel won't schedule the write quickly enough?)? – cjcurrie Jan 10 '13 at 07:25
  • 2
    @cjcurrie The kernel is always involved when writing to a file, but not necessarily when writhing to a stream, since the stream could be bound to something which is handled entirely by the library (such as a stringstream). – Agentlien Jan 10 '13 at 07:42
  • Thank you! I guess this is why John Cormack went on for so long about file paging at QuakeCon '11. – cjcurrie Jan 10 '13 at 11:30
  • This is wrong, the sync() function does not *write* anything. It is used to synchronize with the input data, not the output. – Alexis Wilke Mar 20 '15 at 23:10
  • @AlexisWilke `basic_filebuf::sync` is described by the standard as follows: "If a put area exists, calls `filebuf::overflow` to write the characters to the file. If a get area exists, the effect is implementation-defined." Since this post was about the difference between flushing an output stream and calling `sync` on a `basic_filebuf`, I took it to mean a `basic_filebuf` which was set up for writing. – Agentlien Mar 23 '15 at 07:08
  • Yeah, but sync() is bound to any buffer in general, not only file buffer. – mip Aug 14 '16 at 18:41
  • @doc It's true that `basic_filebuf` is based on `basic_streambuf` which has a `sync` which does nothing unless overridden and is not specific to files. On the other hand, the `basic_filebuf` override of this function is defined specifically in terms of files. – Agentlien Aug 17 '16 at 09:43
  • 2
    I would say that the difference is that `flush()` is related to output streams, while `sync()` is related to output buffers. `flush()` basic calls `sync()` of underlying buffer, whether it is file buffer or any other buffer. OP asks about difference between `fstream::flush()` and `fstream::sync()` whereas you describe the difference between `basic_ostream` and `basic_filebuf`, so I don't get what's going on here. – mip Aug 20 '16 at 16:10
5

sync is a member of input streams, all unread characters are cleared from the buffer. flush is a member of output streams and buffered output is passed down to the kernel.

perreal
  • 94,503
  • 21
  • 155
  • 181
4

C++ I/O involves a cooperation between a number of classes: stream, buffer, locale and locale::facet-s.

In particular sync and flush are member function that exist in both stream and streambuf, so beware to what documentation you are referring, since they do different things.

On streams flush tells the stream to tell the buffer (note the redirection) to flush its content onto the destination. This makes sure that no "pending write" remains.

std::endl, when applied to thestream with <<, is no more than a

thestream.put('\n'); thestream.flush();

Always on streams, sync tells the stream to tell the buffer to flush the content (for output) and read (for input) as much as it can to refill the buffer.

Note that -in buffers- sync can be also called internally by overflow to handle the "buffer full" (for output) and "buffer empty" (for input) situations.

I thus sense, sync is much more an "internal" function used in stream to buffer communication and buffer implementation (where it is virtual and overridden in different buffer types), while flush is much more an interface between the stream and the client program.

endl ... is just a shortcut.

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
  • What's the difference between an On STREAM and an Always on STREAM? I'm afraid I don't understand what you mean here. – cjcurrie Jan 10 '13 at 07:40
  • I talked about stream, buffer and other things (locales ...). When saying "on streams" I just mean "and not on buffers". You can use "with" instead of "on" if you prefer. – Emilio Garavaglia Jan 10 '13 at 11:04
0

I've understood it to be as follows:

flush() will get the data out of the library buffers into the OS's write buffers and will eventually result in a full synchronization (the data is fully written out), but it's definitely up to the OS when the sync will be complete.

sync() will, to the extent possible in a given OS, attempt to force full synchronization to come about — but the OS involved may or may not facilitate this.

So flush() is: get the data out of the buffer and in line to be written.
sync() is: if possible, force the data to be definitively written out, now.

That's been my understanding of this, but as I think about it, I can't remember how I came to this understanding, so I'm curious to hear from others, too.

dgellow
  • 692
  • 1
  • 11
  • 18
DWright
  • 9,258
  • 4
  • 36
  • 53
0

What is the difference between calling fstream::flush() and fstream::sync()?

There is none: Both essentially call rdbuf()->pubsync() which then calls std::streambuf::sync(), see links at https://en.cppreference.com/w/cpp/io/basic_fstream

After constructing and checking the sentry object, calls rdbuf()->pubsync()

and https://en.cppreference.com/w/cpp/io/basic_streambuf/pubsync

Calls sync() of the most derived class

The only difference is where the functions are defined: sync is inherited from istream while flush is inherited from ostream (and fstream inherits from both). And of course the return values are different: sync returns an int (0 for ok, -1 for failure) while flush returns a reference to the stream object. But you likely don't care about those anyway.

The naming difference for input and output streams is that for input it "synchronizes" the internal buffer with the input stream (here a file) in case that changed or "flushes" pending changes from the internal buffer to the output stream (again: here a file). I.e. "sync from" and "flush to" made more sense naming wise. But for an iostream

And for completeness (almost) from Emilios answer:

std::endl, when applied to thestream with <<, is no more than a
thestream.put('\n').flush();

So it appends a newline and then calls the streams flush function which then eventually calls the buffers sync function (through pubsync).
Just a shortcut to basically use line buffering, i.e. write (up to) the end of that newline, then flush what was written.

Flamefire
  • 5,313
  • 3
  • 35
  • 70