【发布时间】: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