Is using of MemoryMappedFile instance, opened by MemoryMappedFile.OpenExisting method threadsafe?
.net
Solution
An open view will not be pulled away under you reading it if some other file handle is disposed or the file is even deleted. The view stays valid until you close it explicitly. The same goes for file handles (you can delete a file while handles are still open and working - this is a little known fact).
Suppose it was closed if a different file handle was closed. Then your code reading it would suddenly start generating access violations at random points during its execution. That would be a deeply unsound design.
Btw, your threading is timing-based and therefore broken. But I think you are just trying to create a repro case that can be executed.
Problem
In my WCF service I need to provide functionality of files downloading with supporting of `Range` HTTP header for chunked downloading. The first call to `GetFile` method of service creates new `MemoryMappedFile` instance from file on disk. Let's assume that in time when MMF created by the first request and that request still processing, the second call to `GetFile` method of service opening existing MMF and returning streamed response to client. What happens if MMF will be disposed (and source file closed on MemoryMappedFile disposing) by thread which create it? Should second call successfully read all content from already opened ViewStream or no? I had wrote small test and seems that till MemoryMappedFile opened by `OpenExisting` method, it's lifetime extended and source file keeps opened. Is this true, or I missed some pitfall? I can't find any documentation for such case in MSDN. Update: added additional Thread.Sleep call after existing MMF opened before obtaining MapView of file to simulate threads race ``` private static readonly string mapName = "foo"; private static readonly string fileName = @"some big file"; static void Main(string[] args) { var t1 = Task.Factory.StartNew(OpenMemoryMappedFile); var t2 = Task.Factory.StartNew(ReadMemoryMappedFile); Task.WaitAll(t1, t2); } private static void OpenMemoryMappedFile() { var stream = File.OpenRead(fileName); using (var mmf = MemoryMappedFile.CreateFromFile(stream, mapName, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false)) { Console.WriteLine("Memory mapped file created"); Thread.Sleep(1000); // timeout for another thread to open existing MMF } Console.WriteLine("Memory mapped file disposed"); } private static void ReadMemoryMappedFile() { Thread.Sleep(100); //wait till MMF created var buffer = new byte[1024 * 1024]; //1MB chunk long totalLength = 0; using (var f = File.OpenRead(fileName)) { totalLength = f.Length; } using (var mmf = MemoryMappedFile.OpenExisting(mapName, MemoryMappedFileRights.Read)) { Console.WriteLine("Existing MMF opened successfully"); Thread.Sleep(2000); //simulate threads race using (var viewStream = mmf.CreateViewStream(0, 0, MemoryMappedFileAccess.Read)) { Console.WriteLine("View of file mapped successfully"); File.Delete(Path.GetFileName(fileName)); using (var fileStream = File.Open(Path.GetFileName(fileName), FileMode.CreateNew, FileAccess.Write)) using (var writer = new BinaryWriter(fileStream)) { int readBytes; do { readBytes = viewStream.Read(buffer, 0, buffer.Length); writer.Write(buffer, 0, readBytes); Console.Write("{0:P}% of target file saved\r", fileStream.Length / (float)totalLength); Thread.Sleep(10); //simulate network latency } while (readBytes > 0); Console.WriteLine(); Console.WriteLine("File saved successfully"); } } } } ```