我有一些类似于这个最小复制示例的代码(真实版本生成一些代码并编译它):
#include <fstream>
#include <string>
#include <thread>
#include <vector>
void write(unsigned int thread)
{
std::ofstream stream("test_" + std::to_string(thread) + ".txt");
stream << "test" << std::endl;
stream << "thread" << std::endl;
stream << "bad" << std::endl;
}
void test(unsigned int thread)
{
write(thread);
#ifdef _WIN32
const std::string command = "rename test_" + std::to_string(thread) + ".txt test_renamed_" + std::to_string(thread) + ".txt";
#else
const std::string command = "mv test_" + std::to_string(thread) + ".txt test_renamed_" + std::to_string(thread) + ".txt";
#endif
system(command.c_str());
}
int main()
{
std::vector<std::thread> threads;
for(unsigned int i = 0; i < 5; i++) {
// Remove renamed file
std::remove(("test_renamed_" + std::to_string(i) + ".txt").c_str());
threads.emplace_back(test, i);
}
// Join all threads
for(auto &t : threads) {
t.join();
}
return EXIT_SUCCESS;
}
My understanding is that std::ofstream
should behave in a nice RAII manner and close and flush at the end of the write function. On Linux, it appears to do just this. However, on Windows 10 I get sporadic "The process cannot access the file because it is being used by another process" errors. I've dug into it with procmon and it looks like the file isn't getting closed by the parent process (22224) resulting in the SHARING_VIOLATION
which presumably causes the error:
Although the procmon trace looks like the problem is within my process, I have tried turning off the virus scanner. I have also tried using C-style fopen,fprintf,fclose and also ensuring that the process I'm spawning with system
isn't inheriting file handles somehow by clearing HANDLE_FLAG_INHERIT on the underlying file handle...which leaves me somewhat out of ideas! Any thoughts SO?
我们可以使用Win32 API重写文件写入:
void writeRaw(unsigned int thread)
{
const auto str = "test_" + std::to_string(thread) + ".txt";
auto hFile = CreateFileA(str.c_str(), GENERIC_WRITE,
FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, 0, nullptr);
DWORD ret{};
WriteFile(hFile, str.data(), str.size(), &ret, nullptr);
CloseHandle(hFile);
}
由于 Windows 的工作方式,运行测试仍然会出现文件共享冲突。当最后一个句柄关闭时,文件系统驱动程序执行 IRP_MJ_CLEANUP IOCTL 来完成与文件相关的任何处理。
例如,防病毒软件会尝试扫描该文件(并顺便锁定它=))。附加文档MSDN IRP_MJ_CLEANUP https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/irp-mj-cleanup指出:
需要注意的是,当文件对象的所有句柄都已关闭时,这并不一定意味着该文件对象不再被使用。系统组件(例如缓存管理器和内存管理器)可能保存对文件对象的未完成引用。即使收到 IRP_MJ_CLEANUP 请求后,这些组件仍然可以读取或写入文件。
结论:如果进程在关闭句柄后不久尝试对文件执行某些操作,则预计会在 Windows 中收到文件共享冲突,因为底层系统组件仍在处理文件关闭请求。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)