.net 使用MemoryMappedFile.OpenExisting方法打开的MemoryMappedFile实例是否线程安全?

.net 使用MemoryMappedFile.OpenExisting方法打开的MemoryMappedFile实例是否线程安全?,.net,.net,在我的WCF服务中,我需要提供文件下载功能,支持RangeHTTP头进行分块下载。对GetFile服务方法的第一次调用将从磁盘上的文件创建新的MemoryMappedFile实例。让我们假设,当第一个请求创建MMF并且该请求仍在处理时,第二次调用GetFile方法打开现有MMF并将流式响应返回给客户端。如果MMF将由创建它的线程来处理(并且源文件在MemoryMappedFile处理时关闭),会发生什么情况?第二次调用是否应成功读取已打开的ViewStream中的所有内容 我编写了一个小测试,似

在我的WCF服务中,我需要提供文件下载功能,支持
Range
HTTP头进行分块下载。对
GetFile
服务方法的第一次调用将从磁盘上的文件创建新的
MemoryMappedFile
实例。让我们假设,当第一个请求创建MMF并且该请求仍在处理时,第二次调用
GetFile
方法打开现有MMF并将流式响应返回给客户端。如果MMF将由创建它的线程来处理(并且源文件在MemoryMappedFile处理时关闭),会发生什么情况?第二次调用是否应成功读取已打开的ViewStream中的所有内容

我编写了一个小测试,似乎在使用
OpenExisting
方法打开MemoryMappedFile之前,它的生命周期将延长,源文件将保持打开状态。这是真的,还是我错过了一些陷阱?我在MSDN中找不到任何此类案例的文档

更新:添加了额外的线程。在获得文件的映射视图以模拟线程竞赛之前,在现有MMF打开后进行休眠调用

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

如果释放了其他文件句柄,或者甚至删除了文件,则打开的视图将不会在您阅读它时从下方移开。视图将保持有效,直到您显式关闭它。文件句柄也是如此(当句柄仍然打开并工作时,您可以删除文件-这是一个鲜为人知的事实)

如果关闭了另一个文件句柄,则假定它已关闭。然后,您读取它的代码会在执行过程中突然在随机点生成访问冲突。这将是一个非常不合理的设计


顺便说一句,你的线程是基于时间的,因此被破坏了。但我认为您只是想创建一个可以执行的复制案例。

谢谢您的帮助。我添加了额外的线程竞争模拟,似乎如果现有MMF已打开,但文件视图尚未映射到此MMF,则文件描述符仍保持打开状态,直到使用
OpenExisting
获得的所有MMF都未被释放。