子进程中的间歇性文件访问错误

时间:2014-12-11 14:40:00

标签: c++ file-io

我正在开发一种编译器启动器,其基本操作顺序如下:

  1. 通过网络连接接受一批源文件,并将它们写入本地文件系统上的目录。
  2. 对这些文件执行许多编译器启动(作为子进程)。
  3. 收集编译器生成的文件并将其发回。
  4. 可选择清理。
  5. 虽然编译器启动是并行化的,但步骤1,2,3,4是以严格顺序的方式完成的,不会重叠。

    问题是,在Windows Server 2008 R2 Enterprise上,编译器会间歇性地抱怨某些文件丢失或权限被拒绝,例如: G:

    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 / fcloseCreateFile / WriteFile / CloseHandle重新实现它,但无济于事。< / p>

    我还尝试打开新编写的文件,以便在此功能结束时阅读,希望它可以使操作系统感知或帮助诊断文件访问问题。没有改变;我自己的进程总是打开并成功读取文件但子进程仍然出现间歇性故障。

    在产生编译器之前插入250毫秒的延迟似乎可以严重降低错误的频率,但并不能完全消除它们(而且无论如何250毫秒都是太多了,因为我必须处理交互式请求)。 / p>

    我在清理步骤中也遇到了类似的问题:当删除编译器生成的文件时,我得到了#34;正在使用的文件&#34;错误。但是,这对我来说不那么重要。

    我无法相信这是我所做的独特之处。实际上,我现在正在C ++中重新实现一个最初用Perl编写的服务器。 Perl版本遇到了某些稳定性问题 - 但不是这个特殊问题。这意味着有一些方法可以使文件系统和子进程保持同步。

    我必须做错的事。它是什么?

1 个答案:

答案 0 :(得分:0)

this MSDN文章中所述,文件读取和写入通常由操作系统缓存。可以通过将FILE_FLAG_NO_BUFFERING参数传递给CreateFile方法来关闭缓存。

如果一个人无法访问文件创建过程,则可以通过调用FlushFileBuffers告诉操作系统刷新特定文件的文件缓存。