私の WCF サービスではRange
、チャンク ダウンロード用の HTTP ヘッダーをサポートするファイル ダウンロード機能を提供する必要があります。サービスのメソッドへの最初の呼び出しは、ディスク上のファイルからGetFile
新しいMemoryMappedFile
インスタンスを作成します。MMF が最初の要求によって作成され、その要求がまだ処理されているときにGetFile
、サービスのメソッドへの 2 番目の呼び出しが既存の MMF を開き、ストリーミングされた応答をクライアントに返すと仮定しましょう。MMF を作成したスレッドによって MMF が破棄される (および MemoryMappedFile の破棄時にソース ファイルが閉じられる) とどうなりますか? 2 番目の呼び出しは、既に開いている ViewStream からすべてのコンテンツを正常に読み取る必要がありますか?
私は小さなテストを書いていましたが、MemoryMappedFile がOpenExisting
メソッドによって開かれるまで、その有効期間が延長され、ソース ファイルが開かれたままになるようです。これは本当ですか、それとも落とし穴を見逃しましたか? MSDN でそのような場合のドキュメントが見つかりません。
更新: スレッドの競合をシミュレートするためにファイルの MapView を取得する前に、既存の MMF を開いた後に追加の Thread.Sleep 呼び出しを追加しました
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");
}
}
}
}