一个程序可以同时在同一个 FILE* 上调用 fflush() 吗?

Can a program call fflush() on the same FILE* concurrently?

如果多个线程在同一个 FILE* 变量上同时调用 fflush(),是否会发生任何不好的事情(如未定义行为、文件损坏等)?

澄清:我并不是说同时写入文件。我的意思是同时刷新它。

线程不会并发读取或写入文件(它们只在临界区内写入文件,一次一个线程)。他们只刷新临界区之外,尽快释放临界区,让其他人做其他工作(文件写入除外)。

尽管可能发生一个线程正在写入文件(在临界区内),而另一个线程正在刷新文件(在临界区外)。

答案很简单,您可能不会那样做,因为该文件只有一个 "current position"。你如何跟踪它?文件打开是为了顺序访问还是随机访问?在后一种情况下,您可以多次打开它(每个线程一次),然后设计保持文件结构一致的方法。

您不应该在输入流上调用 fflush(),它会调用未定义的行为,因此我假设该流以写入或更新模式打开。

如果流以更新模式打开("w+""r+"),调用 fflush() 时最后的操作不能是读取。由于流在各种线程中异步使用,如果没有某种形式的进程间通信和同步或锁定,如果您进行任何读取,将很难确保这一点。在更新模式下打开文件仍有正当理由,但请确保在启动 fflush 线程后不进行任何读取。

fflush()不修改当前位置。它只会导致将任何缓冲输出写入系统。流通常受锁保护,因此在一个线程中调用 fflush() 不应弄乱另一个线程执行的输出,但它可能会改变系统写入的时间。如果多个线程输出相同的 FILE*,交错发生的顺序无论如何都是不确定的。此外,如果您使用 fseek() 是同一流的不同线程,您 必须 使用自己的锁以确保 fseek() 和以下输出之间的一致性.

虽然看起来可以,但可能不推荐这样做。您可以在每个线程中的写操作之后,在释放锁之前调用 fflush()

C1 中的流是线程安全的2。在访问流之前需要函数锁定流3

fflush 函数是线程安全的,可以随时从任何线程调用,只要该流是输出流或更新流4.


1 根据当前标准,即 C11。

2(引自:ISO/IEC 9899:201x 7.21.3 Streams 7)
每个流都有一个关联的锁,用于在多个流时防止数据竞争 执行线程访问流,并限制流操作的交错 由多个线程执行。一次只有一个线程可以持有此锁。锁是 可重入:单个线程可能在给定时间多次持有锁。

3(引自:ISO/IEC 9899:201x 7.21.3 Streams 8)
所有读取、写入、定位或查询流位置的函数都会锁定流 在访问它之前。他们在访问完成时释放与流关联的锁 完全的。 可重入:单个线程可能在给定时间多次持有锁。

4(引自:ISO/IEC 9899:201x 7.21.5.2 fflush函数2)
如果 stream 指向输出流或更新流,其中最新的 未输入操作,fflush 函数会导致该流的任何未写入数据 传送到宿主环境写入文件;否则,行为是 未定义。

POSIX.1 和对字符流(由指向 FILE 类型对象的指针表示)进行操作的 C 语言函数 [=24= .1c 以实现重入的方式实现(参见 ISO/IEC 9945:1-1996,§8.2)。

这个要求有一个缺点;由于为了重入而必须将同步构建到函数的实现中,因此它会造成很大的性能损失。 POSIX.1c 通过引入以下 C 语言标准 I/O 函数的高性能但不可重入(可能不安全)版本来解决重入(安全)和性能之间的权衡:getc() 、getchar()、putc() 和 putchar()。不可重入版本命名为getc_unlocked()等,以强调其不安全性。

但请注意,正如其他人所指出的:许多流行的系统(包括 Windows 和 Android)不 POSIX 兼容。

实际的答案似乎是流本身(应该)是线程安全的,但是,如果不是这样,您的问题可能是 fflush 发生(在锁之外)而另一个线程 正在 写入(在临界区内)。

因此,我会使用您正在编码的虚拟机模型,并将 fflush() 也放在关键部分中。