多个线程同时写同一个文件

3
我想知道是否可以使用多线程在同一个文件上写入二进制数据。
FILE *fd = openfile("test");
int SIZE = 1000000000;
int * table = malloc(sizeof(int) * SIZE);
// .. filling the table
fwrite(table, sizeof(*table), SIZE, fd);

我想知道是否可以使用线程,每个线程调用fssek到不同的位置写入同一个文件。有什么想法吗?


阅读fwrite()的文档以了解它是否支持线程安全。如果不支持,您将需要实现自己的互斥锁来保护它。 - Barmar
1
这里似乎缺失了一些东西:int * table = sizeof(sizeof(int) * SIZE); - alk
4个回答

1

fwrite 应该是线程安全的,但你仍然需要一个互斥锁,因为你需要 seek 和 write 是原子的。根据你的平台,你可能有一个带有偏移量的 write 函数,或者你可以在每个线程中打开文件。如果你的代码已经将所有内容都存储在内存中,更好的选择是让每个线程填充到一个大数组中,然后在一切完成时将其写出。


实际上,我已经有一个很大的数组(表),但我想使用线程同时将“int * table”写入我的文件。 - zeomega
你认为这样做会更快吗?我觉得不太可能,因为写操作必须在某个阶段进行序列化。事实上,额外的寻道可能会显著减慢速度。 - Richard Byron

1
fread()fwrite()是线程安全的,但由FILE*表示的流缓冲区不是。因此,您可以使用多个线程访问同一文件,但不能通过相同的FILE*进行访问 - 每个线程必须有自己的FILE*,并且它们所引用的文件必须是可共享的 - 这取决于操作系统。
另一种可能更简单的方法是使用内存映射文件,这样每个线程将文件视为共享内存,并让操作系统处理文件I/O。这与普通文件I/O相比具有显着优势,因为它是真正的随机访问,因此您不需要担心fseek()和顺序读/写等问题。

你是说在多个线程中使用全局文件指针访问 fprintf()fwrite() 不安全吗? - John Strood
@JohnStrood; 我并没有说得那么明确,但是对于使用FILE*的任何函数都适用,因为FILE不是原子对象。此外,该问题要求独立的fseek()操作,并且由于当前文件位置保留在FILE对象中,在这种特殊情况下,如果不将整个寻址/写入序列包装在互斥体中以确保两个线程的操作串行化,那么它是无法工作的。 - Clifford
虽然这可能对一些C99实现来说是正确的,但C2011规定:“所有读取、写入、定位或查询流位置的函数在访问之前会锁定该流。当访问完成时,它们会释放与流关联的锁”(C2011 7.21.2/8)。请注意,这是指锁定,而不是底层文件。 - John Bollinger
@JohnBollinger:我不清楚你指的是回答的哪一部分或后续的评论。那是很久以前的事了 - 我不确定现在是否要更改它,但是你的评论可能需要澄清 - 即C99的确切情况可能是什么? - Clifford
@Clifford,我首先注意到我的关注点是由另一个答案引导到这里的,因此也许这将有助于理解上下文。但我指的是你整个第一段。虽然标准没有明确说明FILE对象是可共享的,但其有关流和流锁定的规定没有可行的解释不会导致这种结果。 - John Bollinger
@JohnBollinger:如果访问被锁定,完全可以在两个线程之间共享单个FILE对象,但是如果这些线程需要独立地进行读取/写入/查找,则这并不是非常有用 - 在每次读取/写入前都需要进行锁定。然而,我对于不依赖于符合C2011标准的库的可用性而不做任何道歉;尤其是在回答这个问题时。 - Clifford

0

fseek和fwrite是线程安全的,因此您可以在不需要额外同步的情况下使用它们。


6
调用fseek然后调用fwrite需要同步。 - William Pursell
1
@WilliamPursell 这取决于具体的实现。如果每个线程都有自己的文件描述符,那么在没有同步的情况下依次调用它们是安全的。 - kraskevich
实现的一个例子? - zeomega
@zeomega,您的意思是指一个可以在没有额外同步的情况下正常工作的实现吗?您只需在每个线程中调用fopen打开相同的文件即可。 - kraskevich

0

让每个线程打开文件,并确保它们写入不同的位置,最后让每个线程关闭文件,你就完成了。

更新:

这在IX系统上有效,至少是这样。


1
你有一个小例子吗? - zeomega

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接