如果多个线程同时在同一个fflush()
变量上调用FILE*
,可能会发生任何不良事件(如未定义的行为,文件损坏等)吗?
澄清:我不是指同时写文件。我只是说要同时冲洗它。
线程不会同时读取或写入文件(它们只将文件写入临界区,一次一个线程)。它们只在临界区外冲洗,以便更快地释放关键部分,以便让其他人完成其他工作(文件写入除外)。
虽然可能会发生一个线程正在写文件(在关键部分内),而另一个线程正在刷新文件(在关键部分之外)。
答案 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
放入一个关键部分。