【问题标题】:File that ensures that its content is complete when read读取时确保其内容完整的文件
【发布时间】:2016-04-03 05:19:39
【问题描述】:

我需要创建包含由正在运行的进程 (A) 提供的数据的文件。它将被一个或多个其他进程(BC)读取。第一个想法是简单地创建一个文件并将数据写入其中。但是现在恐怕虽然进程 A 写入文件并且进程 BC 或许多其他进程会读取它,但它可能只有部分内容。

我想知道是否有办法让我的进程A 创建一个文件,该文件的行为类似于内核创建的/sys 中的文件。

我也想过创建一个命名管道。但我不希望写入文件的任何更新被排队。

另一个想法是创建某种信号量文件,但由于其他进程数量未知,我担心如果一个读取进程死亡或文件更新速度变慢,它们会造成死锁。

【问题讨论】:

    标签: linux


    【解决方案1】:

    您最好的选择可能是使用一个临时文件,然后在写入完成后将其移动以替换旧文件。所以,在类似 shell 的伪代码中:

    $ write_new_file_state tmp_file
    $ mv tmp_file file
    

    这确保了文件file 仅以原子方式更新——它要么包含旧内容,要么已被覆盖,并包含新内容。文件的读者将看到旧内容或新内容,但不会看到不完整的内容,或两者的某种组合。

    请注意,如果您这样做,您需要让消费者关闭他们的文件描述符(Go 中的f.Close())并明确地重新打开。这样做的原因是,如果他们不这样做,他们仍将持有对现已删除的旧版本文件的引用(文件描述符指的是文件对象,而不是名称,因此覆盖文件不会改变现有文件文件描述符参考)。

    【讨论】:

    • 谢谢!这种行为在所有文件系统上都相同吗?
    • 我很确定这是 Linux 内核保证的属性。引用man 2 rename:“如果newpath 已经存在,它将被原子地替换(受一些条件的影响;请参阅下面的错误),因此尝试访问newpath 的另一个进程不会找到它失踪。”此外,“[i]f newpath 存在,但由于某种原因操作失败,rename() 保证保留 newpath 的实例。”
    【解决方案2】:

    一个常见的技巧是使用rename 系统调用以原子方式将文件放置到位。这意味着您必须将文件写入临时文件名,然后重命名。

    【讨论】:

      猜你喜欢
      • 2014-04-29
      • 1970-01-01
      • 2014-08-06
      • 2013-02-07
      • 1970-01-01
      • 2016-06-21
      • 2018-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多