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