两个线程将相同内容写入同一文件是否安全?

问题描述 投票:1回答:2

假设程序具有缓存机制,其中在某些特定计算的末尾,该程序会将该计算的输出写入磁盘,以免在以后重新运行该程序时重新计算。这样做是为了进行大量计算,并将每个输出保存到单独的文件中(每个计算一个)。数据通过标准C ++流写入文件:

    void* data = /* result of computation */;
    std::size_t dataSize = /* result of computation */;
    std::string cacheFile = /* unique filename for to this computation */;

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

问题:对于多个线程(或进程),对于相同的计算和相同的输出文件,同时尝试进行此操作是否安全?

该计算是确定性的,因此写入给定文件的数据将始终相同。因此,只要至少一个成功,某些线程或进程是否无法写入文件就没有关系。在我进行的手动测试中,没有程序失败或数据损坏发生,并且始终使用正确的内容创建文件,但这可能与平台有关。作为参考,在我们的特定情况下,数据的大小范围为2到50 KB。

c++ io thread-safety fstream diskcache
2个回答
1
投票

多个线程(或进程)同时尝试进行相同的计算,使用相同的输出文件是否安全?

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

针对您的问题的正确解决方案:

  1. 写入目标目录中具有唯一名称的临时文件。
  2. rename临时文件为其最终名称。如果rename失败,则文件已经存在。

0
投票

多个线程同时写入文件并不安全。线程写入文件的顺序也是不可预测的。

但是,如果您使用某种线程同步并且只有一个类来管理文件,则可以这样做。您可以使用rename对象,在写入文件之前将其锁定。这是一个非常简单的类可以做到这一点:

std::mutex

#include <fstream> #include <vector> #include <mutex> class FileManager { public: FileManager(const std::string& filepath) : mFs(filepath, std::ios::binary) {} ~FileManager() = default; void Write(const std::vector<char> &data) { std::lock_guard<std::mutex> lk(mMutex); mFs.write(&data[0], data.size()); } private: std::ofstream mFs; std::mutex mMutex; }; int main() { FileManager fm("D:\\Temp\\data.dat"); std::vector<char> data = { 'H','e','l','l','o' }; fm.Write(data); } 将在写操作期间锁定您的互斥锁,以确保它是原子的。它也是RAII,因此在超出范围时会解锁互斥锁。

使用共享指针或对线程中相同std::lock_guard对象的引用。

© www.soinside.com 2019 - 2024. All rights reserved.