我正在开发一种编译器启动器,其基本操作顺序如下:
- 通过网络连接接受一批源文件,并将它们写入本地文件系统的目录。
- 对这些文件执行多次编译器启动(作为子进程)。
- 收集编译器生成的文件并将它们发回。
- (可选)清理。
虽然编译器启动是并行的,但第 1、2、3、4 步是严格按顺序执行的,不会重叠。
问题是,在 Windows Server 2008 R2 Enterprise 上,编译器会间歇性地提示某些文件丢失或权限被拒绝,例如。例如:
some_file1.h(20) : fatal error C1083: Cannot open include file: 'some_file1.h': No such file or directory
或:
c1xx : fatal error C1083: Cannot open source file: 'some_file3.cpp': Permission denied
通常,与给定文件有关的故障会在多次编译器启动时重复出现。我从未在开发机器上遇到过这些故障。
编译器提示的所有文件在我事后检查时实际上并不存在。我还保存了编译器启动的完整日志,包括命令行、启动目录和环境变量。当我手动重新运行它们时,它们运行良好。
这一切看起来像是操作系统对文件系统数据进行了一些缓存,使得并非所有最新数据始终对其他进程(包括子进程)可用。
写入文件的代码如下所示:
bool Session::receive_file(
unsigned long long file_size,
std::string const& full_path)
{
std::ofstream ofs(full_path, std::ios::binary | std::ios::trunc);
if (!ofs)
{
skip_input(file_size);
return false;
}
char buf[4096];
while (file_size)
{
std::streamsize s = sizeof buf;
if (static_cast<unsigned long long>(s) > file_size)
s = file_size;
read_buffer(buf, s);
file_size -= s;
if (!(ofs.write(buf, s)))
{
skip_input(file_size);
return false;
}
}
ofs.close();
if (!ofs)
return false;
return true;
}
我尝试用 fopen
/fwrite
/fclose
和 CreateFile
/WriteFile< 重新实现它
/CloseHandle
但无济于事。
我还尝试在此函数的末尾打开新写入的文件以供阅读,希望它能让操作系统恢复正常或有助于诊断文件访问问题。没有改变;我自己的进程总是打开并成功读取文件,但子进程仍然遇到间歇性故障。
在生成编译器之前插入 250 毫秒的延迟似乎可以显着降低错误的频率,但并不能完全消除它们(无论如何 250 毫秒太过分了,因为我必须处理交互式请求)。
我在清理步骤中也遇到了类似的问题:删除编译器生成的文件时,出现“文件正在使用”错误。然而,这对我来说不是那么重要。
我不敢相信我正在做的事情是独一无二的。实际上,我现在正在用 C++ 重新实现一个最初用 Perl 编写的服务器。 Perl 版本遇到了某些稳定性问题——但不是这个特殊问题。这意味着有多种方法可以使文件系统和子进程保持同步。
一定是我做错了什么。这是什么?
最佳答案
如 this 中所述MSDN 文章,文件读写一般由操作系统缓存。可以通过将 FILE_FLAG_NO_BUFFERING 参数传递给 CreateFile 来关闭缓存。方法。
如果无法访问文件创建过程,可以通过调用 FlushFileBuffers 告诉操作系统刷新特定文件的文件缓存。 .
关于c++ - 子进程中的间歇性文件访问错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27425407/