Does the MemoryMappedFile instance opened by the MemoryMappedFile.OpenExisting function be thread safe?

In my WCF service, I need to provide file upload functionality with support for the Range HTTP header for batch upload. The first call to the GetFile service GetFile creates a new instance of MemoryMappedFile from a file on disk. Suppose that at a time when the MMF created by the first request and this request is still being processed, the second call to the GetFile method GetFile open the existing MMF and return a stream response to the client. What happens if the MMF is deleted (and the source file is closed when the MemoryMappedFile is disposed) by the thread that creates it? Should the second call successfully read all content from an already open ViewStream or not?

I wrote a small test and, it seems, before opening the MemoryMappedFile using the OpenExisting method, it is extended for life and the source file remains open. Is this true, or did I miss some trap? I can not find the documentation for this case on MSDN.

Update : added an additional call to Thread.Sleep after opening the MMF until receiving a MapView file to simulate a stream 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"); } } } } 
+4
source share
1 answer

An open view will not be deleted when reading if any other file descriptor is deleted or the file is deleted. The view remains valid until you explicitly close it. The same applies to file descriptors (you can delete a file while the handles are still open and working - this is a little-known fact).

Suppose it was closed if another file descriptor was closed. Then your code reading it will suddenly start generating access violations at random points during its execution. That would be deeply unfounded.

Btw, your streaming is time based and therefore broken. But I think that you are just trying to create an example playback that can be executed.

+3
source

Source: https://habr.com/ru/post/1497884/


All Articles