了解对fflush()的需求以及与之相关的问题 [英] Understanding the need for fflush() and problems associated with it

查看:96
本文介绍了了解对fflush()的需求以及与之相关的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是使用fflush()的示例代码:

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);
}

我对fflush()所了解的只是它是用于刷新输出缓冲区的库函数.我想知道使用fflush()的基本目的是什么,在哪里可以使用它.我主要是想知道使用fflush()会出现什么问题.

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().

推荐答案

很难说出fflush的使用有问题"(过多吗?). 各种事物都可能成为问题,也可能成为问题,这取决于您的目标和方法. fflush的意图可能是一种更好的方法.

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.

首先要考虑的是,fflush仅在输出流上定义.输出流将要写入文件的内容"收集到较大的(ish)缓冲区中,然后将该缓冲区写入文件中.此后收集和写作的目的是通过两种方式提高速度/效率:

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:

  • 在现代OS上,跨越用户/内核保护边界会受到一定的惩罚(系统必须更改CPU中的某些保护信息,等等).如果您进行大量的OS级写调用,则每次都要付出一定的代价.例如,如果您收集了8192个左右的单个写入一个大缓冲区,然后进行一次调用,则可以消除大部分开销.
  • 在许多现代的OS上,每个OS写入调用都将尝试以某种方式优化文件性能,例如,通过发现将一个短文件扩展为一个较长的文件,最好将磁盘块从磁盘上的点A到磁盘上的点B,以便更长的数据可以连续容纳. (在较旧的操作系统上,这是您可以手动执行的单独的碎片整理"步骤.您可以将其视为现代的OS,进行动态的即时碎片整理.)如果要写入500个字节,然后再写入200个字节,然后是700,依此类推,它将完成很多工作;但是,如果您打个大电话(例如8192字节),则OS可以分配一次大块,然后将所有内容放在该块中,而不必在以后重新进行碎片整理.

因此,提供您的C库及其stdio流实现的人员会在您的OS上做任何适当的事情,以找到合理最佳"的块大小,并将所有输出收集到该大小的块中. (今天,数字4096、8192、16384和65536往往是不错的数字,但是它实际上取决于操作系统,有时还取决于基础文件系统.请注意,更大"并不总是更好":例如,一次以4 GB的数据块流式传输数据可能比以64 KB的数据块流式传输数据更糟糕.)

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.)

但这会带来问题.假设您正在写入文件,例如带有日期和时间戳记和消息的日志文件,并且您的代码将在以后继续写入该文件,但是现在,它希望暂停一段时间并让日志分析器读取日志文件的当前内容.一种选择是使用fclose关闭日志文件,然后使用fopen再次打开日志文件,以便以后添加更多数据.但是,将所有待处理的日志消息推送到基础OS文件中效率更高,但保持文件处于打开状态.这就是fflush的作用.

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.

缓冲还会产生另一个问题.假设您的代码有一些错误,有时会崩溃,但是您不确定它是否会崩溃.并假设您已经写了一些东西,并且 this 数据进入底层文件系统非常重要.在调用可能会崩溃的潜在错误代码之前,可以调用fflush将数据推送到操作系统. (有时这对于调试很有用.)

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.)

或者,假设您使用的是类似Unix的系统,并且有一个fork系统调用.此调用将复制整个用户空间(对原始进程进行克隆). stdio缓冲区位于用户空间中,因此在fork调用时,克隆具有与原始进程相同的,但尚未写入的缓冲区.同样,解决问题的一种方法是在执行fork之前使用fflush将缓冲的数据推出.如果所有内容都在fork之前出现,则没有可重复的内容.新鲜的克隆不会再尝试写入缓冲的数据,因为它不再存在.

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.

您添加的fflush-越多,您击败原始数据收集大块数据的想法就越多.就是说,您正在权衡:大块代码效率更高,但会引起其他问题,因此您要做出决定:在这里效率较低,要解决的问题比单纯的效率更重要".您呼叫fflush.

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.

有时候问题只是在调试软件".在这种情况下,您可以使用setbufsetvbuf之类的功能来更改stdio流的缓冲行为,而不必重复调用fflush.这比添加许多fflush调用更为方便(需要更改的代码更少,甚至不需要更改,您可以使用标志来控制set-buffering调用),因此可以认为这是使用问题(或过多的问题)". -使用)的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".

这篇关于了解对fflush()的需求以及与之相关的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆