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

时间:2016-08-20 11:36:35

标签: c multithreading file stdio fflush

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

澄清:我不是指同时写文件。我只是说要同时冲洗它。

线程不会同时读取或写入文件(它们只将文件写入临界区,一次一个线程)。它们只在临界区外冲洗,以便更快地释放关键部分,以便让其他人完成其他工作(文件写入除外)。

虽然可能会发生一个线程正在写文件(在关键部分内),而另一个线程正在刷新文件(在关键部分之外)。

5 个答案:

答案 0 :(得分:39)

C 1 中的流是线程安全的 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)
如果流指向输出流或最新的流更新流 如果没有输入操作,fflush函数会导致该流的任何未写入数据 要传递到主机环境以写入文件;否则,行为是 未定义。

答案 1 :(得分:12)

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

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

但是请注意,其他人已经注意到:许多流行的系统(包括Windows和Android)都不符合POSIX。

答案 2 :(得分:9)

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

如果流在更新模式("w+""r+")中打开,则在致电fflush()时,最后一项操作不得为读取。由于流以异步方式用于各种线程,因此如果进行任何读取,如果没有某种形式的进程间通信和同步或锁定,则很难确保这种情况。在更新模式下打开文件仍然有正当理由,但请确保在启动fflush线程后不进行任何读取。

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

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

答案 3 :(得分:1)

非常简单的答案,你可能不这样做,因为文件只有一个当前位置"。你如何跟踪它?是打开文件进行顺序访问还是随机?在后一种情况下,您可以多次打开它(每个线程一个),然后设计保持文件结构一致的方法。

答案 4 :(得分:0)

实际的答案似乎是流本身(意味着)是线程安全的,但是,如果不是这种情况,那么你的问题可能是Runnable发生(在锁定之外),而另一个线程写(在一个关键部分内)。

因此,我将使用您正在编码的虚拟机模型,并将fflush放入一个关键部分。