【问题标题】:MemoryMappedFile doesn't work with 2 processes?MemoryMappedFile 不适用于 2 个进程?
【发布时间】:2012-04-03 08:13:00
【问题描述】:

我用MemoryMappedFile 做了一个简单的测试,msdn 说:

2 个进程,1 个内存映射文件:

  • 第一个进程添加字符串“1”
  • 第一个进程等待
  • 第二个进程添加字符串“2”并终止
  • 第一个进程现在读取整个内存映射文件

流程A:

using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
            {
                bool mutexCreated;
                Mutex mutex = new Mutex(true, "testmapmutex", out mutexCreated);
                using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                {
                    BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8);
                    writer.Write("1");
                }
                mutex.ReleaseMutex();
                Console.WriteLine("Start Process B and press ENTER to continue.");
                Console.ReadLine();
                mutex.WaitOne();
                using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                {
                    BinaryReader reader = new BinaryReader(stream, Encoding.UTF8);
                    Console.WriteLine("Process A says: {0}", reader.ReadString());
                    Console.WriteLine("Process B says: {0}", reader.ReadString());
                }
                mutex.ReleaseMutex();
            }

流程 B:

 using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
                {
                    Mutex mutex = Mutex.OpenExisting("testmapmutex");
                    mutex.WaitOne();
                    using (MemoryMappedViewStream stream = mmf.CreateViewStream(1, 0))
                    {
                        BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8);
                        writer.Write("2");
                    }
                    mutex.ReleaseMutex();
                }

结果是:

胡?

“1”、“2”在哪里?

但是,如果我运行 ONLY 第一个进程(不激活进程 B),我会得到:

我错过了什么?

我希望看到:

Process A says: 1
Process B says: 2

【问题讨论】:

  • 在 MSDN 的示例中,他们写数字,你写字符串。传递给 CreateViewStream 的偏移量可能是错误的!这将解释 BinaryReader 返回的垃圾
  • @Steve 他们没有考虑任何偏移量...我只是将 bool 更改为 string..
  • 但是,如果内存服务,UTF8 是两个字节,您从第 1 个字节开始写入第二个字符串,覆盖第一个字符串的第二个字节。
  • @steve utf8 中的 8 是每个字符的位数

标签: c# .net-4.0 memory-mapped-files


【解决方案1】:

您正在与 BinaryWriter.Write(string) 的实现细节作斗争。它首先写入字符串的长度,以便 BinaryReader 在读回字符串时知道需要读取多少个字符。对于短字符串,例如“1”,它会写入一个字节来存储长度。

所以你传递给 CreateViewStream() 的偏移量是错误的,传递 1 将使它覆盖进程 A 写入的字符串的一部分。你看到的笑脸字符是 (char)1 的字形.进程B写入的字符串的长度字节。

内存映射文件在托管代码中很麻烦。您通常通过声明一个结构来设置布局并使用指针来访问视图来读取和写入它们,但这需要不安全的代码。流对于一大块内存来说是一个非常糟糕的抽象,但却是一个必要的邪恶。这也是 MMF 花了这么长时间才在 .NET 中可用的原因。

【讨论】:

  • 你不应该写这样的代码。一个明显的失败模式是 A 写入的字符串比 B 所指的要长。
  • 感谢您的回复,如果我写在 A writer.Write("1"); - 你实际上是在告诉我从 B 上的适当索引中读取。但是我怎么知道索引?
  • 这正是重点。只有当它们映射的内存被可预测地分割时,MMF 才能正常工作。想想只有值类型的结构。如果你真的想实现长度不可预测的流,那么管道是一个更好的选择。但是,您可以通过让 A 写入长度来完成这项工作。 B 可以阅读并知道在哪里写。您需要两个视图。
  • hans 但是当我将12 作为整数时--它也不起作用,而且它们都-大小相同...?
  • 汉斯!使用整数,我可以看到它在工作:) 在 A 中我写了 1,在 B 中我跳过了 4 个字节(作为 int),一切都很好。现在我将尝试使用字符串...(我怎么知道长度?是 xxx.length 就足够了吗?-在非 unicode 中...)
【解决方案2】:

编辑

我注意到ProcessB 的代码中有一件明显奇怪的事情。这段代码

using (MemoryMappedViewStream stream = mmf.CreateViewStream(1, 0))

first 字节创建一个视图,但 .NET 中的字符串是 2 个字节。我认为让1->2 变为 2 就足够了。因此,ProcessB 视图相对于映射文件开头的偏移量将是已经插入“1”字符串之后ProcessA

在你的情况似乎重叠他们。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多