gpt4 book ai didi

c - 了解对 fflush() 的需求以及与之相关的问题

转载 作者:太空狗 更新时间:2023-10-29 16:36:48 28 4
gpt4 key购买 nike

下面是使用 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() 会出现什么问题。

最佳答案

很难说 fflush 的使用“可能会带来什么问题”(过度?) .根据您的目标和方法,各种事情都可能成为或成为问题。 fflush 的意图可能是一个更好的方式来看待这个问题。是。

首先要考虑的是fflush仅在输出流上定义。输出流将“要写入文件的内容”收集到一个大(ish)缓冲区中,然后将该缓冲区写入文件。这种收集和写入稍后的重点是通过两种方式提高速度/效率:

  • 在现代操作系统上,跨越用户/内核保护边界会受到一些惩罚(系统必须更改 CPU 中的某些保护信息等)。如果您进行大量操作系统级别的写入调用,您将为每个调用付出代价。如果您将大约 8192 个单独的写入收集到一个大缓冲区中,然后进行一次调用,则可以消除大部分开销。
  • 在许多现代操作系统上,每个操作系统写入调用都会尝试以某种方式优化文件性能,例如,通过发现您已将一个短文件扩展为一个较长的文件,并且最好将磁盘块从 A 点移动到将磁盘指向磁盘上的 B,以便可以连续容纳较长的数据。 (在较旧的操作系统上,这是一个单独的“碎片整理”步骤,您可以手动运行。您可以将其视为现代操作系统进行动态、即时的碎片整理。)如果您要写入 500 个字节,然后再写入 200 个字节,然后是 700 等等,它会做很多这样的工作;但是如果你用 8192 字节进行一次大调用,操作系统可以一次分配一个大块,然后把所有东西都放在那里,以后不必重新整理碎片。

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

    但这会产生一个问题。假设您正在写入一个文件,例如带有日期和时间戳记和消息的日志文件,并且您的代码稍后将继续写入该文件,但现在,它想要暂停一段时间并让日志分析器读取日志文件的当前内容。一种选择是使用 fclose关闭日志文件,然后 fopen再次打开它以便稍后附加更多数据。不过,将任何挂起的日志消息推送到底层 OS 文件但保持文件打开的效率更高。就是这样 fflush做。

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

    或者,假设你在一个类 Unix 系统上,并且有一个 fork系统调用。此调用复制整个用户空间(克隆原始进程)。 stdio 缓冲区位于用户空间中,因此在 fork 发生时,克隆具有与原始进程相同的已缓冲但尚未写入的数据。称呼。再次,解决问题的一种方法是使用 fflush在执行 fork 之前将缓冲的数据推出.如果一切都在 fork 之前,没有什么可复制的;新的克隆永远不会尝试写入缓冲数据,因为它不再存在。

    更多 fflush -es 你添加的越多,你就越能打败收集大量数据的最初想法。也就是说,您正在权衡:大块更有效,但会导致一些其他问题,因此您做出决定:“在这里效率较低,解决比单纯效率更重要的问题”。您拨打 fflush .

    有时问题只是“调试软件”。在这种情况下,而不是重复调用 fflush ,您可以使用类似 setbuf 的函数和 setvbuf改变 stdio 流的缓冲行为。这比添加大量 fflush 更方便(更少,甚至不需要更改代码——您可以使用标志控制设置缓冲调用)。调用,因此可以将其视为“ fflush 的使用(或过度使用)问题”。

    关于c - 了解对 fflush() 的需求以及与之相关的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16780908/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com