【问题标题】:Is it safe for two threads to write identical content to the same file?两个线程将相同的内容写入同一个文件是否安全?
【发布时间】:2020-08-03 23:42:02
【问题描述】:

假设一个程序有一个缓存机制,在某个特定计算结束时,程序将该计算的输出写入磁盘以避免以后重新运行程序时重新计算它。它为大量计算执行此操作,并将每个输出保存到单独的文件中(每个计算一个,文件名通过计算参数的散列确定)。数据使用标准 C++ 流写入文件:

    void* data = /* result of computation */;
    std::size_t dataSize = /* size of the result in bytes */;
    std::string cacheFile = /* unique filename for this computation */;

    std::ofstream out(cacheFile, std::ios::binary);
    out << dataSize;
    out.write(static_cast<const char *>(data), dataSize);

计算是确定性的,因此写入给定文件的数据将始终相同。

问题:多个线程(或进程)同时尝试此操作、进行相同的计算并使用相同的输出文件是否安全?某些线程或进程是否无法写入文件无关紧要,只要至少有一个成功,并且只要所有程序都处于有效状态即可。

在我运行的手动测试中,没有发生程序故障或数据损坏,并且始终使用正确的内容创建文件,但这可能与平台有关。作为参考,在我们的具体案例中,数据的大小范围为 2 到 50 KB。

【问题讨论】:

  • 保险箱是什么意思?当两个线程将相同的数据写入文件时,数据会被写入两次。如果你同时写,顺序是不可预测的。例如。两个线程都写“123\n”。结果可能是 "1123\n23\n" 或 "123\n123\n" 或 "123123\n\n" 或 ....
  • 为什么要这样做?我宁愿确保一个线程成功写入而其他线程不成功。目前,当您必须首先将其内容重构为有意义的内容时,这对于进一步处理文件来说听起来像是一场噩梦
  • @ThomasSablik 只有在使用std::ios::app 打开文件时才会发生这种情况,不是吗?
  • @idclev463035818 这用于将 JIT 编译的代码缓存到磁盘,以提高运行时性能。至于确保只有一个线程写入磁盘,这在具有互斥锁的单个程序中是可能的,但如果在多个进程中执行则不行。
  • @CorentinSchreiber 我试过了,你是对的。在我的系统(Linux、ext4、gcc)上,如果没有std::ios::app,它不会混淆输出

标签: c++ io thread-safety fstream diskcache


【解决方案1】:

多个线程(或进程)同时尝试此操作、相同的计算以及使用相同的输出文件是否安全?

当多个线程尝试写入同一个文件时,这是一种竞争条件,因此您最终可能会得到一个损坏的文件。无法保证 ofstream::write 是原子的,并且取决于特定的文件系统。

针对您的问题的强大解决方案(适用于多个线程和/或进程):

  1. 写入目标目录中具有唯一名称的临时文件(以便临时文件和最终文件位于同一文件系统中,rename 不会移动数据)。
  2. rename 将临时文件改成最终名称。如果存在,它将替换现有文件。非便携式renameat2 更灵活。

【讨论】:

  • 谢谢,这可能是我们将采用的解决方案,因为它只需要可移植的功能。您在第一句话中是否有您的主张的参考资料?
  • @CorentinSchreiber 这是常识。没有标准要求文件系统写入来写入整个缓冲区并同时是原子的。尽管这是一个非常理想的功能。
【解决方案2】:

可以在同一进程中同步线程以使用线程同步写入一个文件。但是,这在不同的进程之间是不可能的,所以最好避免它。 C++ 标准库中没有任何东西可以用于此目的。

操作系统确实提供了用于锁定文件的特殊功能,这些文件保证是原子的(如 Linux 上的 lockf 或 Windows 上的 LockFile(Ex))。您可能想查看它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    相关资源
    最近更新 更多