7

I need my code (C++, on linux) to call a second executable, having previously written an output file which is read by the second program. Does the naïve approach,

std::ofstream out("myfile.txt");
// write output here
out.close();
system("secondprogram myfile.txt");

suffer from a potential race condition, where even though out.close() has executed, the file cannot immediately be read by secondprogram? If so, what is the best practice for resolving this?

Three notes:

  • If this is file-system-dependent, I'm interested in the behaviour on ext3 and tmpfs.
  • Clearly there are other reasons (file permissions etc.) why the second program might fail to open the file; I'm just interested in the potential for a race condition.
  • The hardcoded filename in the example above is for simplicity; in reality I use mkstemp.
Chris Johnson
  • 10,469
  • 4
  • 31
  • 35
  • Yes it is guaranteed. Are you sure the issue is about that? Did you `strace` your program? – Basile Starynkevitch Mar 26 '13 at 14:41
  • @BasileStarynkevitch I haven't (yet) had an issue: I just wanted to check that I was not going to get one future. Can you elaborate on whether it is C++, linux, the file system, or something else that is making this guarantee? – Chris Johnson Mar 26 '13 at 14:51
  • I'd say all of them have to guarantee parts of this: Your C++ implementation has to guarantee that the buffer is flushed and `close()` returns only after the relevant syscall for `close`ing a file has returned, the kernel has to guarantee that after the syscall returns, the file is openable and all changes made through the old handle are visible, and the VFS has to guarantee to handle the caches correctly. I'd agree with @BasileStarynkevitch : All of this should hold and you shouldn't run into problems. – us2012 Mar 26 '13 at 14:58
  • Great - thanks. If one of you writes an answer to that effect I will accept it. – Chris Johnson Mar 26 '13 at 15:02

3 Answers3

3

Once the file has been closed, all the written data is guaranteed to be flushed from the buffers of the ofstream object (because at that point you can destroy it without any risk of losing whatsoever data, and actually closing the file is internally done by the destructor if needed). This does not mean that the data will at this point be physically on the disk (it will probably not, because of caching behavior of the OS disk drivers), but any program running in the same OS will be able to read the file consistently (as the OS will then perform the reading from the cached data). If you need to flush the OS buffers to the disk (which is not needed for your secondprogram to correctly read the input file), then you might want to look at the sync() function in <unistd.h>.

Ale
  • 1,727
  • 14
  • 26
1

There is a potential failure mode that I missed earlier: You don't seem to have a way of recovering when the file cannot be opened by secondprogram. The problem is not that the file might be locked/inconsistent after close() returns, but that another program, completely unrelated to yours, might open the file between close() and system() (say, an AV scanner, someone greping through the directory containing the file, a backup process). If that happens, secondprogram will fail even though your program behaves correctly.

TL/DR: Even though everything works as expected, you have to account for the case that secondprogram may not be able to open the file!

us2012
  • 16,083
  • 3
  • 46
  • 62
0

According to cplusplus.com the function will return, when all data has been written to disk. So there should be no race-condition.

bash.d
  • 13,029
  • 3
  • 29
  • 42
  • 1
    I don't think that's true. What it means by 'Any pending output sequence is written to the physical file.' is probably that the internal buffer of the `fstream` is flushed, so all changes to the file will be visible to everyone else. I'd be highly surprised if the standard mandated that `close()` forces the operating system to write out its caches to disk immediately. – us2012 Mar 26 '13 at 14:45
  • 1
    Your link to cplusplus.com doesn't strictly say that the data will be written by the time that fstream::close returns. It almost certainly isn't: see http://stackoverflow.com/questions/705454/does-linux-guarantee-the-contents-of-a-file-is-flushed-to-disc-after-close – Chris Johnson Mar 26 '13 at 14:48
  • This is why I stated _according to_, I have not implemented the C++ stdlib and so can't tell you. – bash.d Mar 26 '13 at 14:49