简体   繁体   中英

Intermittent file access errors in child processes

I am developing a sort of compiler launcher whose basic sequence of operation is as follows:

  1. Accept a batch of source files over a network connection and write them to a directory on the local file system.
  2. Execute a number of compiler launches (as child processes) over these files.
  3. Collect files produced by the compilers and send them back.
  4. Optionally, clean up.

Although compiler launches are parallelized, steps 1, 2, 3, 4 are done in a strictly sequential fashion and do not overlap.

The problem is, on Windows Server 2008 R2 Enterprise, compilers make intermittent complaints about some files being missing or permission denied, eg:

some_file1.h(20) : fatal error C1083: Cannot open include file: 'some_file1.h': No such file or directory

or:

c1xx : fatal error C1083: Cannot open source file: 'some_file3.cpp': Permission denied

Usually, a failure pertaining to a given file is repeated across several compiler launches. I never experience these failures on the development machine.

All files compilers complain are not there actually are when I check afterwards. I also keep a full log of compiler launches, including command lines, start directories and environment variables. When I rerun them manually, they run fine.

What all this looks like, is that the operating system does some caching of file system data in such a fashion that not all freshest data is always available to other processes (including children).

The code that writes a file looks like this:

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;
}

I tried to reimplement it with fopen / fwrite / fclose and CreateFile / WriteFile / CloseHandle but to no avail.

I also tried to open the freshly-written file for reading at the end of this function in hope that it would bring the OS to senses or will help diagnose file access problems. Nothing changed; my own process always opened and read the file successfully but child processes still experienced intermittent failures.

A delay of 250 ms inserted before spawning the compilers seems to seriously reduce the frequency of errors but does not eliminate them completely (and anyway 250 ms is hell too much because I've got to handle interactive requests).

I also experience a similar trouble with the cleanup step: when removing files generated by compilers I get "file in use" errors. That's of lesser priority to me, however.

I can't believe that it is something unique what I am doing. Actually, I am now reimplementing in C++ a server that was originally written in Perl. The Perl version suffered from certain stability problems - but not this particular problem. That means there are ways to keep file system and child processes in sync.

Something I must be doing wrong. What is it?

As described in this MSDN article, file reads and writes are in general cached by the operating system. One can turn the caching off by passing the FILE_FLAG_NO_BUFFERING parameter to the CreateFile method.

If one does not have access to the file creation process, it is possible to tell the operating system to flush the file cache for a specific file by calling FlushFileBuffers .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM