简体   繁体   English

如何在c#.net 4中正确使用内存共享?

[英]How do I use memory sharing correctly in c#.Net 4?

I don't know if it's because of old posts or just lack of understanding but I seem to be coming across all kinds of bad info when it comes to using memory maps in .Net4. 我不知道这是由于过时的帖子还是仅仅是由于缺乏理解,但是在使用.Net4中的内存映射时,我似乎遇到了各种各样的错误信息。 Maybe as soon as .Net4 was released in beta everyone started posting about it and things were different in .Net4 beta? 也许.Net4在Beta中发布后,每个人都开始发布它,而.Net4 beta中的情况有所不同吗? Or maybe I just don't know what I'm talking about and they are all right but I can't seem to figure out the correct way to use memory maps. 或者,也许我只是不知道我在说什么,它们还不错,但是我似乎无法弄清楚使用内存映射的正确方法。 I'm looking for a way to use the same code on BOTH apps so the code is generic and one of the two apps would not be considered a primary (that creates something the other app needs). 我正在寻找一种在两个应用程序上使用相同代码的方法,因此该代码是通用的,并且两个应用程序之一将不被视为主要代码(这会创建其他应用程序需要的东西)。 Example 1 is a prime example of the idea I DO NOT want to achieve (it's just there as an example of what I've found). 示例1是我不想实现的想法的主要示例(它只是我发现的一个示例)。

In the end I want both apps to run over and over again accessing a memory stream (memory map) to read and write data as it needs to. 最后,我希望两个应用程序都能一次又一次地运行,以访问内存流(内存映射)以根据需要读写数据。 When the last app using the memory map is exiting the map should be closed and deleted. 当使用内存映射的最后一个应用程序退出时,应关闭并删除该映射。

I have seen the following examples trying to show how to correctly use memory maps. 我已经看到了以下示例,试图说明如何正确使用内存映射。 I don't know what they are all doing but the overloads they are using seem to be wrong too. 我不知道他们都在做什么,但是他们使用的过载似乎也是错误的。 :/ :/

Example 1: 范例1:

This would be used on app1.exe where the memory is first created. 这将在第一次创建内存的app1.exe上使用。

using System.IO;
using System.IO.MemoryMappedFile;

MemoryMappedFile MemoryMapped = MemoryMappedFile.CreateFromFile(
  new FileStream(@"C:\temp\Map.mp", FileMode.Create),
  "MyMemMapFile",
  1024 * 1024,
  MemoryMappedFileAccess.ReadWrite
);

//Write to the memory map
MemoryMappedViewAccessor FileMapView = MemoryMapped.CreateViewAccessor();
int Number = 1234;

FileMapView.Write(0, Number);
FileMapView.Write<Container>(4, ref MyContainer);

This would be used on app2.exe where the memory is accessed later. 这将在稍后访问内存的app2.exe上使用。

using System.IO;
using System.IO.MemoryMappedFile;

MemoryMappedFile MemoryMapped = MemoryMappedFile.CreateOrOpen(
  new FileStream(
    @"C:\temp\Map.mp",
    FileMode.Create),
  "MyMemMapFile",
  1024 * 1024,
  MemoryMappedFileAccess.ReadWrite
);

// Create the map view and read it
using (MemoryMappedViewAccessor FileMap = MemoryMapped.CreateViewAccessor())
{
  Container NewContainer = new Container();
  FileMap.Read<Container>(4, out NewContainer);
}

Example 2: 范例2:

using System.IO;
using System.IO.MemoryMappedFiles;

class Test
{
    static void Main()
    {
        FileStream file = File.OpenRead("Test.cs");
        using (MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile
               (file, "PEIMAGE", file.Length, MemoryMappedFileAccess.Read))
        {
            using (var viewStream = mappedFile.CreateViewStream
                   (0, file.Length, MemoryMappedFileAccess.Read))
            {
                // read from the view stream
            }
        }
    }
}

After doing a bunch of research elsewhere, trying to weed out the old code that is incorrect from over the years (back in the .Net4 beta days) I managed to come up with the following. 在其他地方进行了大量研究之后,尝试清除多年来(在.Net4 beta时代)不正确的旧代码,我设法提出以下建议。 This gives a basic great example of how to handle the memory map, memory view streams, read method, and write method. 这给出了如何处理内存映射,内存视图流,读取方法和写入方法的基本示例。 In this example I also use a user defined structure to pass data from one application to the other. 在此示例中,我还使用用户定义的结构将数据从一个应用程序传递到另一个应用程序。

How To Use This In Application #1 (write) 如何在应用程序1中使用它(写)

Say we wanted application #1 to write some data to the memory stream. 假设我们希望应用程序1将一些数据写入内存流。 In the Form_Load AFTER connecting to the memory stream just use something like the following... 在连接到内存流的Form_Load AFTER中,只需使用如下所示的内容...

UpdateInfoPacket packet = new UpdateInfoPacket();
packet.JobName = "This is my test job.";
packet.NumberOfFiles = 40;
packet.Status = 'F';
WriteMemoryMap(packet);

How To Use This In Application #2 (read) 如何在应用程序2中使用它(已阅读)

Say we wanted application #2 to read some data from the memory stream. 假设我们希望应用程序2从内存流中读取一些数据。 In the Form_Load AFTER connecting to the memory stream just use something like the following... 在连接到内存流的Form_Load AFTER中,只需使用如下所示的内容...

UpdateInfoPacket packet;
ReadMemoryMap(out packet);

Complete Solution 完整的解决方案

using System;
using System.Windows.Forms;
using System.IO.MemoryMappedFiles;
using System.IO;
using System.Runtime.InteropServices;

namespace MyMemoryApplication
{
    public partial class Form1 : Form
    {
        private struct UpdateInfoPacket
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string JobName;

            public char Status;

            public int NumberOfFiles;
        }

        private MemoryMappedFile m_memMap = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            m_memMap = ConnectToMemoryMap("MyMemoryMapName");
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_memMap != null) m_memMap.Dispose();
        }

        private MemoryMappedFile ConnectToMemoryMap(string mapName)
        {
            MemoryMappedFile memMap = null;
            try
            {
                memMap = MemoryMappedFile.OpenExisting(mapName);
            }
            catch (FileNotFoundException ex)
            {
                if (ex.Message != "Unable to find the specified file.")
                {
                    //BIG ERROR, report it
                    System.Diagnostics.Debug.WriteLine("Error " + ex.Message);
                }
                memMap = null;
            }

            //Create the memory map if needed
            try
            {
                if (memMap == null)
                    memMap = MemoryMappedFile.CreateNew(mapName, 10000);
            }
            catch (Exception ex)
            {
                //BIG ERROR, report it
                System.Diagnostics.Debug.WriteLine("Error " + ex.Message);

                memMap = null;
            }

            return memMap;
        }

        private int PacketSize()
        {
            UpdateInfoPacket packet = new UpdateInfoPacket();
            int size = Marshal.SizeOf(packet);
            return size;
        }

        private byte[] PacketToBytes(UpdateInfoPacket packet)
        {
            int size = Marshal.SizeOf(packet);
            byte[] array = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(packet, ptr, true);
            Marshal.Copy(ptr, array, 0, size);
            Marshal.FreeHGlobal(ptr);
            return array;
        }

        private UpdateInfoPacket BytesToPacket(byte[] packet)
        {
            UpdateInfoPacket structure = new UpdateInfoPacket();

            int size = Marshal.SizeOf(structure);
            IntPtr ptr = Marshal.AllocHGlobal(size);

            Marshal.Copy(packet, 0, ptr, size);

            structure = (UpdateInfoPacket)Marshal.PtrToStructure(ptr, structure.GetType());
            Marshal.FreeHGlobal(ptr);

            return structure;
        }

        private void ReadMemoryMap(out UpdateInfoPacket packet)
        {
            packet = new UpdateInfoPacket();

            MemoryMappedViewStream memStream = null;
            try
            {
                //Make sure there is a map first
                if (m_memMap == null) return;

                //Create the view stream
                memStream = m_memMap.CreateViewStream();
                memStream.Seek(0, SeekOrigin.Begin);

                //Create the object to read from the memory map
                using (BinaryReader reader = new BinaryReader(memStream))
                {
                    //Read the data from memory in bytes
                    byte[] rawPacket = reader.ReadBytes(PacketSize());

                    //Convert the byte data to the structure
                    if (rawPacket != null) packet = BytesToPacket(rawPacket);
                }
            }
            catch (Exception ex)
            {
                //BIG ERROR, report it
                System.Diagnostics.Debug.WriteLine("Error " + ex.Message);
            }
        }

        private void WriteMemoryMap(UpdateInfoPacket packet)
        {
            MemoryMappedViewStream memStream = null;
            try
            {
                //Make sure there is a map first
                if (m_memMap == null) return;

                //Create the view stream
                memStream = m_memMap.CreateViewStream();
                memStream.Seek(0, SeekOrigin.Begin);

                //Create the object to write to the memory map
                using (BinaryWriter writer = new BinaryWriter(memStream))
                {
                    //Convert the structure to a byte array
                    byte[] rawPacket = PacketToBytes(packet);

                    //Write the byte array to memory
                    writer.Write(rawPacket);
                }
            }
            catch (Exception ex)
            {
                //BIG ERROR, report it
                System.Diagnostics.Debug.WriteLine("Error " + ex.Message);
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM