我有两个.NET 4.0 WinForms应用程序(主要)从共享的MemoryMappedFiles读取地理数据。最终用户可以自由启动其中一个应用程序,也可以同时运行这两个应用程序。第一个打开的应用程序创建了命名的MemoryMapFile-s,第二个打开已经存在的应用程序。 但是,打开现有的名为MemoryMappedFile似乎不可靠。它大约80%的情况下工作,但大约20%的情况下它失败了FileNotFoundException。 症状不能安全再现,当它失败并成功时似乎是纯粹的运气。
以下是两个应用程序用于获取MemoryMappedFiles的代码:
private static MemoryMappedFile GetMemoryMappedFile(string filePath)
{
string mapName = filePath; // I have also tried here @"Global\myfile", no difference
MemoryMappedFile mmf = null;
try
{
// When the first app executes this step, it always succeeds.
// When the second app comes here, it fails as it should.
mmf = MemoryMappedFile.CreateFromFile(filePath, FileMode.OpenOrCreate,
mapName, HundredMB, MemoryMappedFileAccess.ReadWrite);
}
catch (IOException)
{
try
{
// Opening the already existing named MemoryMappedFile by the SECOND app.
// This line fails about 20% of the time.
mmf = MemoryMappedFile.OpenExisting(mapName,
MemoryMappedFileRights.ReadWrite);
}
catch (FileNotFoundException ex)
{
Console.WriteLine("Yet again, could not open MMF. Life sux.");
}
}
return mmf;
}
答案 0 :(得分:3)
你所描述的似乎是一个非常可能的案例。你所拥有的是一种竞争条件。例如,在CreateFromFile
上抛出异常的代码告诉您该文件存在。然后,另一个进程在此代码到达OpenExisting
之前关闭文件。然后调用OpenExisting
并因为文件不再存在而失败。这是您需要为其编写代码的有效案例。
答案 1 :(得分:3)
string mapName = filePath;
这看起来非常可疑。 filePath 字符串应始终引用文件的绝对路径名。像“c:\ foo \ bar \ baz.bin”一样,从不使用相对文件名,例如“baz.bin”。像“Global \ myfile”这样的名称不是路径名,而是内存映射名。这是另一个进程用于打开映射的内容,它不知道或不关心充当映射的后备存储的实际文件。
这种失败的一种非常常见的方式是当您的程序的工作目录(Environment.CurrentDirectory)未设置在您希望设置的位置时。除了突然看到CreateFromFile()调用失败之外,它有一个改变的诀窍而不会意识到。
因此,请选择一个非常适合您应用的唯一地图名称来解决您的问题。以及使用完整路径名选择的文件。通常存储在AppData中,您可以在没有UAC提升的情况下具有写入权限的文件夹。
答案 2 :(得分:2)
如何翻转逻辑?由于MMF的创建应该是一次性的事情,但现有的开放应该是更常见的情况,也许这会有用吗?
private static MemoryMappedFile GetMemoryMappedFile(string filePath)
{
var mapName = filePath; // I have also tried here @"Global\myfile", no difference
MemoryMappedFile mmf = null;
try
{
// When the first app executes this step, it fails as it should.
// Opening the already existing named MemoryMappedFile by the SECOND app.
mmf = MemoryMappedFile.OpenExisting(mapName, MemoryMappedFileRights.ReadWrite);
}
catch (FileNotFoundException)
{
try
{
// When the first app executes this step, it always succeeds.
mmf = MemoryMappedFile.CreateFromFile(
filePath,
FileMode.OpenOrCreate,
mapName,
HundredMB,
MemoryMappedFileAccess.ReadWrite);
}
catch (IOException ex)
{
Console.Error.WriteLine("Yet again, could not open MMF. Life sux: " + ex);
}
}
return mmf;
}
答案 3 :(得分:1)
我是这个问题的作者,而且我是个傻瓜。 MMF按照预期工作。失败是由第二种方法(很久以前由我编写)引起的,我创建了MMF-s,但我在那里应用了不同的MMF命名约定。问题中的代码失败(正确),因为某些MMF是在我的第二个方法中以错误的名称创建的。
我不会删除这个问题,因为仍有一些有价值的答案可能有助于后来的读者。非常感谢所有花时间回答的人。