在Linux和Mac OS X上使用多个进程安全地写入和读取同一文件

时间:2013-03-20 09:02:06

标签: file file-io io inode

我有三个流程可以在Linux和Mac OS X环境中持续运行。一个进程(Downloader)每30秒下载并存储一个大型XML文件的本地副本。另外两个进程(Workers)使用存储的XML文件进行输入。每个工人都会随机启动并运行。由于XML文件很大,下载需要很长时间。工人们也需要很长时间来阅读和解析它。

设置进程的最安全的方法是什么,以便在工人尝试阅读时,Downloader不会破坏存储的文件?

1 个答案:

答案 0 :(得分:4)

对于使用基于inode的文件系统的Linux和Mac OS X计算机,使用临时文件在下载数据时存储数据(并且是不完整的状态)。下载完成后,使用原子操作将临时文件移动到其最终位置。

有关详细信息,当一个进程(例如Downloader)写入其他进程(例如Workers)主动读取的文件时,需要注意两件事:

  1. 确保在Downloader完成编写之前,Workers不会尝试读取文件。
  2. 确保在工作人员阅读时,下载程序不会更改文件。
  3. 使用临时文件可以容纳这两点。

    对于更具体的示例,当Downloader主动拉动XML文件时,让它写入同一设备/磁盘*上的临时位置(例如'data-storage.tmp'),最终文件将存储在该位置。完成文件的下载和编写后,让Downloader通过atomic (aka linearizable)重命名命令(如bash的mv)将其移动到最终位置(例如'data-storage.xml')。

    * 请注意,临时文件需要与最终文件位置在同一设备上的原因是为了确保inode编号保持不变,并且重命名可以原子方式完成。

    此方法确保在下载/写入文件时,Workers将不会看到它,因为它位于.tmp位置。由于重命名与inode一起工作的方式,它还确保打开文件的任何Worker继续查看旧内容,即使新版本的数据存储文件已到位。

    Downloader会在重命名时将'data-storage.xml'指向新的inode编号,但Worker将继续从前一个inode编号访问'data-storage.xml',从而继续使用该文件在那个州。同时,在Downloader完成重命名后打开新副本“data-storage.xml”的任何Worker将看到新inode编号中的内容,因为它现在是文件系统中直接引用的内容。因此,两个Worker可以从相同的文件名(data-storage.xml)读取,但每个文件将根据文件首次打开时指向文件名的inode来查看文件内容的不同(和完整)版本。

    为了看到这一点,我创建了一组简单的示例脚本,用于在github上演示此功能。它们还可用于测试/验证使用临时文件解决方案在您的环境中工作。


    重要的一点是,特定设备上的文件系统至关重要。如果您使用的是Linux或Mac计算机但使用的是FAT文件系统(例如,usb拇指驱动器),则此方法将无效。