Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is "sequential" file I/O with System.IO.File helper methods safe?

Tags:

c#

.net

io

I just saw this question: Is it safe to use static methods on File class in C#?. To summarize OP has an IOException because file is in use in this ASP.NET code snippet:

var text= File.ReadAllText("path-to-file.txt");
// Do something with text
File.WriteAllText("path-to-file.txt");

My first thought has been it's a simple concurrent access issue because of multiple ASP.NET overlapping requests. Something I'd solve centralizing I/O into a synchronized thread-safe class (or dropping files in favor of something else). I read both answers and when I was about to downvote one of them then I saw who those users are and I thought what the h* and stopped.

I'll cite them both (then please refer to original answers for more context).

For this OP paragraph:

I am guessing that the file read operation sometimes is not closing the file before the write operation happens [...]

An answer says:

Correct. File systems do not support atomic updates well [...] Using FileStream does not help [...] File has no magic inside. It just uses FileStream wrapped for your convenience.

However I don't see any expectancy for an atomic operation (read + subsequent write) and parallel (because of partially overlapping multi-threaded requests) may cause concurrent accesses. Even an atomic I/O operation (read + write) will have exactly same issue. OK FileStream may be asynchronous but it's not how File.ReadAllText() and File.WriteAllText() use it.

The other answer made me much more perplex, it says:

Although according to the documentation the file handle is guaranteed to be closed by this method, even if exceptions are raised, the timing of the closing is not guaranteed to happen before the method returns: the closing could be done asynchronously.

What? MSDN says method will open, read and close file (also in case of exceptions). Is it ever possible that such method will close file asynchronously? Will OS defer CloseHandle()? In which cases? Why?

In short: is it just a misunderstanding or CloseHandle() is asynchronous? I'm missing something extremely important?

like image 286
Adriano Repetti Avatar asked Sep 07 '15 07:09

Adriano Repetti


2 Answers

If you look at the CloseHandle documentation, it states that each method which opens a handle has a description of how it should be closed:

The documentation for the functions that create these objects indicates that CloseHandle should be used when you are finished with the object, and what happens to pending operations on the object after the handle is closed. In general, CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system.

When you look at the CreateFile docs, this is what it says:

When an application is finished using the object handle returned by CreateFile, use the CloseHandle function to close the handle. This not only frees up system resources, but can have wider influence on things like sharing the file or device and committing data to disk.

I would find it peculiar that CloseHandle would yield that the underlying handle is closed while asynchronously retaining the file for additional checks. This would weaken many guarantees the OS makes to the callers, and would be a source for many bugs.

like image 107
Yuval Itzchakov Avatar answered Nov 03 '22 06:11

Yuval Itzchakov


The first two quotes in your question are not supposed to be related. When File.* is done, or when you close a FileStream, the file is unlocked immediately. There never is any kind of "lingering". If there was you could never safely access the same file again without rebooting.

May answer assumes that the code in the question is being run multiple times in parallel. If not, that code is clearly safe.

However I don't see any expectancy for an atomic operation ... Even an atomic I/O operation (read + write) will have exactly same issue.

That's true. I don't know why I made a statement about that in my answer (it's correct, though. Just not relevant).

the timing of the closing is not guaranteed to happen before the method returns: the closing could be done asynchronously.

I don't know why he said that because it's not correct under any circumstances that I can think of. Closing a handle has an immediate effect.


I think your understanding of the situation is completely accurate. Apparently, our answers were unclear and slightly misleading... Sorry about that.

like image 40
usr Avatar answered Nov 03 '22 05:11

usr