1

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

4

2 回答 2

2

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

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

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

  1. 写入目标目录中具有唯一名称的临时文件(以便临时文件和最终文件位于同一文件系统中,rename以不移动数据)。
  2. rename临时文件为其最终名称。如果存在,它将替换现有文件。非便携式renameat2更灵活。
于 2020-04-21T09:32:50.460 回答
0

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

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

于 2020-04-21T11:13:37.570 回答