Understanding the need for fflush () and related issues

The following 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 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 the output buffer. I want to know what is the main purpose of using fflush (), and where can I use it. And basically, I am interested to know what problems with using fflush () can be.

+8
c fflush
source share
3 answers

It's a little hard to say what could be the problem with (excessive?) Using fflush . All sorts of things can be or become problems depending on your goals and approaches. Probably the best way to look at this is with fflush .

First of all, keep in mind that fflush is only defined for output streams. The output stream collects “things to write to the file” into a large (ish) buffer, and then writes this buffer to the file. The point of this assembly and recording later is to improve speed / efficiency in two ways:

  • In modern operating systems, there is some penalty for crossing the user / kernel protection border (the system must change some protection data in the CPU, etc.). If you make a large number of calls at the OS level, you pay a fine for each. If you collect, say, 8192 or so individual records into one large buffer, and then make one call, you will delete most of this overhead.
  • On many modern operating systems, every write call to the OS will try to somehow optimize file performance, for example, by finding that you have expanded a short file to a longer one, and it would be useful to move the disk block from point A on the disk to indicate B on disk so that longer data can touch. (In older OSs, this is a separate “defragmentation” step, which you can run manually. You can think about it, since a modern OS performs dynamic, instant defragmentation.) If you were to write, say, 500 bytes, and then another 200, and then 700, etc., he will do most of this work; but if you make one big call with, say, 8192 bytes, the OS can allocate one big block once, and put everything there and you won’t have to defragment it later.

So, the people who provide your C library and its implementation of the stdio stream do whatever suits your OS to find the “reasonably optimal” block size and put all the output in a piece of that size. (The numbers 4096, 8192, 16384, and 65536 are often generally good, but it really depends on the OS, and sometimes the underlying file system. Note that “more” is not always “better”: stream data in chunks of four gigabytes at a time will probably work worse than doing it in 64Kbytes chunks, for example.)

But this creates a problem. Suppose you are writing a file, for example, a log file with date and time stamps and messages, and your code will continue to write to this file later, but right now it wants to pause for a while and let the 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 to add additional data later. However, it is more efficient to use any pending log messages in the base OS file, but keep the file open. What fflush does.

Buffering also poses another problem. Suppose your code has an error and sometimes it crashes, but you are not sure that it is about to crash. And suppose that you wrote something, and it is very important that this data go to the underlying file system. You can call fflush to move data to the OS before calling potentially dangerous code that could be corrupted. (Sometimes this is good for debugging.)

Or suppose you are using 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 but not yet written data that the original process had during the fork call. Here's another way to solve the problem - use fflush to output buffered data just before you fork . If everything remains before fork , there is nothing to duplicate; the new clone will never attempt to write buffered data since it no longer exists.

The more fflush - if you add, the more you defeat the original idea of ​​collecting large chunks of data. That is, you make a compromise: large chunks are more effective, but cause some other problems, so you decide: "Be less effective here to solve a problem more important than just efficiency." You call fflush .

Sometimes the problem is simply "debugging the software." In this case, instead of calling fflush multiple times, you can use functions such as setbuf and setvbuf to change the stdio stream's buffering behavior. This is more convenient (less or even no code changes are required - you can control the call with the buffering setting with the flag) than adding a lot of fflush calls fflush that they can be considered as "a problem using (or excessive -use) fflush ".

+35
source share

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

The first thing to consider is that fflush is only defined at the output of the threads.

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

For output streams, fflush () forces all user space to write buffered data for a given data stream or update stream through the stream, the main write function. For input streams, fflush () discards any buffered data that was extracted from the main file but was not used by the application . The open status of the stream does not change. Thus, when used in input, fflush just discards it.

Here is a demo for illustration:

 #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); } 
+1
source share

fflush() empties the buffers associated with the stream. if you, for example, let the user enter some data in a very short period of time (milliseconds) and write some things to a file, the buffers for writing and reading may have a part of the “balance” left in themselves. you call fflush() then to flush all the buffers and force the standard outputs to make sure the next input you get is what the user clicked.

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

-one
source share

All Articles