Understanding the need for fflush() and problems associated with it
Asked Answered
V

3

18

Below is sample code for using fflush():

#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <io.h>

void flush(FILE *stream);

int main(void)
{
   FILE *stream;
   char msg[] = "This is a test";

   /* create a file */
   stream = fopen("DUMMY.FIL", "w");

   /* write some data to the file */
   fwrite(msg, strlen(msg), 1, stream);

   clrscr();
   printf("Press any key to flush DUMMY.FIL:");
   getch();

   /* flush the data to DUMMY.FIL without closing it */
   flush(stream);

   printf("\nFile was flushed, Press any key to quit:");
   getch();
   return 0;
}

void flush(FILE *stream)
{
     int duphandle;

     /* flush the stream's internal buffer */
     fflush(stream);

     /* make a duplicate file handle */
     duphandle = dup(fileno(stream));

     /* close the duplicate handle to flush the DOS buffer */
     close(duphandle);
}

All I know about fflush() is that it is a library function used to flush an output buffer. I want to know what is the basic purpose of using fflush(), and where can I use it. And mainly I am interested in knowing what problems can there be with using fflush().

Vinic answered 27/5, 2013 at 21:45 Comment(3)
when you use printf() without any new line, it will probably won't print immediately. if you know your program may crash any second, you can use fflush() (or newlines...). I don't think this is the common usage though.Wad
Only problem I can think of is that doing it too often is bad for performance. Also, you should know that closing a file or program termination implies an automatic flush. A short-running program will seldom need to call fflush() explicitly.Reinaldo
The entire purpose of stdio is to provide application-side buffering for the read() and write() system calls. Any time you have buffering you need a flush operation. The only identifiable 'problem' with it is forgetting to use it when you need to, or perhaps overusing it, e.g. inside loops instead of at the end of the loop.Recourse
Z
59

It's a little hard to say what "can be problems with" (excessive?) use of fflush. All kinds of things can be, or become, problems, depending on your goals and approaches. Probably a better way to look at this is what the intent of fflush is.

The first thing to consider is that fflush is defined only on output streams. An output stream collects "things to write to a file" into a large(ish) buffer, and then writes that buffer to the file. The point of this collecting-up-and-writing-later is to improve speed/efficiency, in two ways:

  • On modern OSes, there's some penalty for crossing the user/kernel protection boundary (the system has to change some protection information in the CPU, etc). If you make a large number of OS-level write calls, you pay that penalty for each one. If you collect up, say, 8192 or so individual writes into one large buffer and then make one call, you remove most of that overhead.
  • On many modern OSes, each OS write call will try to optimize file performance in some way, e.g., by discovering that you've extended a short file to a longer one, and it would be good to move the disk block from point A on the disk to point B on the disk, so that the longer data can fit contiguously. (On older OSes, this is a separate "defragmentation" step you might run manually. You can think of this as the modern OS doing dynamic, instantaneous defragmentation.) If you were to write, say, 500 bytes, and then another 200, and then 700, and so on, it will do a lot of this work; but if you make one big call with, say, 8192 bytes, the OS can allocate a large block once, and put everything there and not have to re-defragment later.

So, the folks who provide your C library and its stdio stream implementation do whatever is appropriate on your OS to find a "reasonably optimal" block size, and to collect up all output into chunk of that size. (The numbers 4096, 8192, 16384, and 65536 often, today, tend to be good ones, but it really depends on the OS, and sometimes the underlying file system as well. Note that "bigger" is not always "better": streaming data in chunks of four gigabytes at a time will probably perform worse than doing it in chunks of 64 Kbytes, for instance.)

But this creates a problem. Suppose you're writing to a file, such as a log file with date-and-time stamps and messages, and your code is going to keep writing to that file later, but right now, it wants to suspend for a while and let a log-analyzer read the current contents of the log file. One option is to use fclose to close the log file, then fopen to open it again in order to append more data later. It's more efficient, though, to push any pending log messages to the underlying OS file, but keep the file open. That's what fflush does.

Buffering also creates another problem. Suppose your code has some bug, and it sometimes crashes but you're not sure if it's about to crash. And suppose you've written something and it's very important that this data get out to the underlying file system. You can call fflush to push the data through to the OS, before calling your potentially-bad code that might crash. (Sometimes this is good for debugging.)

Or, suppose you're on a Unix-like system, and have a fork system call. This call duplicates the entire user-space (makes a clone of the original process). The stdio buffers are in user space, so the clone has the same buffered-up-but-not-yet-written data that the original process had, at the time of the fork call. Here again, one way to solve the problem is to use fflush to push buffered data out just before doing the fork. If everything is out before the fork, there's nothing to duplicate; the fresh clone won't ever attempt to write the buffered-up data, as it no longer exists.

The more fflush-es you add, the more you're defeating the original idea of collecting up large chunks of data. That is, you are making a tradeoff: large chunks are more efficient, but are causing some other problem, so you make the decision: "be less efficient here, to solve a problem more important than mere efficiency". You call fflush.

Sometimes the problem is simply "debug the software". In that case, instead of repeatedly calling fflush, you can use functions like setbuf and setvbuf to alter the buffering behavior of a stdio stream. This is more convenient (fewer, or even no, code changes required—you can control the set-buffering call with a flag) than adding a lot of fflush calls, so that could be considered a "problem with use (or excessive-use) of fflush".

Zelazny answered 27/5, 2013 at 23:31 Comment(0)
A
2

Well, @torek's answer is almost perfect, but there's one point which is not so accurate.

The first thing to consider is that fflush is defined only on output streams.

According to man fflush, fflush can also be used in input streams:

For output streams, fflush() forces a write of all user-space buffered data for the given output or update stream via the stream's underlying write function. For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application. The open status of the stream is unaffected. So, when used in input, fflush just discard it.

Here is a demo to illustrate it:

#include<stdio.h>

#define MAXLINE 1024

int main(void) {
  char buf[MAXLINE];

  printf("prompt: ");
  while (fgets(buf, MAXLINE, stdin) != NULL)
    fflush(stdin);
    if (fputs(buf, stdout) == EOF)
      printf("output err");

  exit(0);
}
Assess answered 2/3, 2015 at 15:17 Comment(4)
Later on in the same man page, it says: "The standards do not specify the behavior for input streams. Most other implementations behave the same as Linux."Nervous
I'll note as well that the Linux extension is a good thing to be able to do, but in BSD, we put it into the nonstandard fpurge function, which is defined on both input and output streams.Zelazny
The C spec has "If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.". fflush(input_stream) is undefined behavior. The man page relates to a subset of compilers, not C in general.Farflung
if (fputs(buf, stdout) == EOF) printf("output err"); is questionable for if printing fails, a following print to the same stream is suspect. Printing to stderr has a better change of being noticed.Farflung
H
0

fflush() empties the buffers related to the stream. if you e.g. let a user input some data in a very shot timespan (milliseconds) and write some stuff into a file, the writing and reading buffers may have some "reststuff" remaining in themselves. you call fflush() then to empty all the buffers and force standard outputs to be sure the next input you get is what the user pressed then.

reference: http://www.cplusplus.com/reference/cstdio/fflush/

Hexangular answered 27/5, 2013 at 21:59 Comment(4)
what can be the problems in using it?Vinic
fflush() is a standard C function and is supported on Linux.Letters
This answer is completely wrong and suggests that fflush can be used for input. It cannot.Bolide
It does not suggest that Oo it says that it empties the buffers, that are connected with the streams to make sure your next input becomes rightHexangular

© 2022 - 2024 — McMap. All rights reserved.