C#.Net通信共享内存映射文件Memory Mapped

目录
  • 内存映射文件究竟是个什么?
  • .Net 共享内存 内存映射文件原理
  • C# .Net 共享内存 演示代码
  • C# .Net 进程间通信共享内存
    • IMServer_Message.exe 代码
    • IMServer_State.exe代码

节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。

内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当。实际上,任何想要共享数据的通信模型都会在幕后使用它。

内存映射文件究竟是个什么?

内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作。物理存储是文件管理,而内存映射文件是操作系统级内存管理。

优势:

1.访问磁盘文件上的数据不需执行I/O操作和缓存操作(当访问文件数据时,作用尤其显著);

2.让运行在同一台机器上的多个进程共享数据(单机多进程间数据通信效率最高);

利用文件与内存空间之间的映射,应用程序(包括多个进程)可以通过直接在内存中进行读写来修改文件。.NET Framework 4 用托管代码按照本机Windows函数访问内存映射文件的方式来访问内存映射文件,管理 Win32 中的内存映射文件

有两种类型的内存映射文件:

  • 持久内存映射文件

持久文件是与磁盘上的源文件关联的内存映射文件。在最后一个进程使用完此文件后,数据将保存到磁盘上的源文件中。这些内存映射文件适合用来处理非常大的源文件。

  • 非持久内存映射文件

非持久文件是未与磁盘上的源文件关联的内存映射文件。当最后一个进程使用完此文件后,数据将丢失,并且垃圾回收功能将回收此文件。这些文件适用于为进程间通信(IPC) 创建共享内存。

1)在多个进程之间进行共享(进程可通过使用由创建同一内存映射文件的进程所指派的公用名来映射到此文件)。

2)若要使用一个内存映射文件,则必须创建该内存映射文件的完整视图或部分视图。还可以创建内存映射文件的同一部分的多个视图,进而创建并发内存。为了使两个视图能够并发,必须基于同一内存映射文件创建这两个视图。

3)如果文件大于应用程序用于内存映射的逻辑内存空间(在 32 位计算机上为2GB),则还需要使用多个视图。

有两种类型的视图:流访问视图和随机访问视图。使用流访问视图可对文件进行顺序访问;在使用持久文件时,随机访问视图是首选方法。

.Net 共享内存 内存映射文件原理

通过操作系统的内存管理器访问的,因此会自动将此文件分隔为多个页,并根据需要对其进行访问。您不需要自行处理内存管理。如下图:

C# .Net 共享内存 演示代码

   //持久内存映射文件:基于现有文件创建一个具有指定公用名的内存映射文件
    using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\内存映射文件.data", FileMode.Open, "公用名"))
    {
        //通过指定的 偏移量和大小 创建内存映射文件视图服务器
        using (var accessor = mmf.CreateViewAccessor(offset, length)) //偏移量,可以控制数据存储的内存位置;大小,用来控制存储所占用的空间
        {
            //Marshal提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。
            int size = Marshal.SizeOf(typeof(char));
            //修改内存映射文件视图
            for (long i = 0; i < length; i += size)
            {
                char c= accessor.ReadChar(i);
                accessor.Write(i, ref c);
            }
        }
    }
    //另一个进程或线程可以,在系统内存中打开一个具有指定名称的现有内存映射文件
    using (var mmf = MemoryMappedFile.OpenExisting("公用名"))
    {
        using (var accessor = mmf.CreateViewAccessor(4000000, 2000000))
        {
            int size = Marshal.SizeOf(typeof(char));
            for (long i = 0; i < length; i += size)
            {
                char c = accessor.ReadChar(i);
                accessor.Write(i, ref c);
            }
        }
    }
//非持久内存映射文件:未映射到磁盘上的现有文件的内存映射文件
    using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
    {
        bool mutexCreated;
        //进程间同步
        Mutex mutex = newMutex(true, "testmapmutex", out mutexCreated);
        using (var stream = mmf.CreateViewStream()) //创建文件内存视图流 基于流的操作
        {
            var writer = newBinaryWriter(stream);
            writer.Write(1);
        }
        mutex.ReleaseMutex();
        Console.WriteLine("Start Process B and press ENTER to continue.");
        Console.ReadLine();
        mutex.WaitOne();
        using (MemoryMappedViewStream stream = mmf.CreateViewStream())
        {
            var reader = newBinaryReader(stream);
            Console.WriteLine("Process A says: {0}", reader.ReadBoolean());
            Console.WriteLine("Process B says: {0}", reader.ReadBoolean());
        }
        mutex.ReleaseMutex();
    }
    using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
    {
         Mutex mutex = Mutex.OpenExisting("testmapmutex");
        mutex.WaitOne();
       using (var stream = mmf.CreateViewStream(1, 0))//注意这里的偏移量
        {
            var writer = newBinaryWriter(stream);
            writer.Write(0);
        }
        mutex.ReleaseMutex();
    }

C# .Net 进程间通信共享内存

完整示例:C#共享内存非持久化方式通讯的例子,通讯时的线程和进程控制也没有问题。

  • 先启动消息服务IMServer_Message,
  • 再启动状态服务IMServer_State,
  • IMServer_Message回车一次(创建共享内存公用名和公用线程锁,并视图流方式写共享内存),
  • IMServer_State回车一次(获取共享内存并视图流方式写、视图访问器写入结构体类型)
  • 并立刻IMServer_Message再回车一次(读取刚刚写入的信息),
  • 观察IMServer_State屏显变化并等待(线程锁)约5s(线程锁被释放)后
  • 在IMServer_Message上观察屏显(显示刚刚写入共享内存的信息)

IMServer_Message.exe 代码

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Threading;
namespace IMServer_Message
{
    /// <summary>
    /// 用于共享内存方式通信的 值类型 结构体
    /// </summary>
    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    }
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.Write("请输入共享内存公用名(默认:testmap):");
            string shareName = Console.ReadLine();
            if (string.IsNullOrEmpty(shareName))
                shareName = "testmap";
            using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(shareName, 1024000,MemoryMappedFileAccess.ReadWrite))
            {
                bool mutexCreated;
                //进程间同步
                var mutex = new Mutex(true, "testmapmutex", out mutexCreated);
                using (MemoryMappedViewStream stream = mmf.CreateViewStream()) //创建文件内存视图流
                {
                    var writer = new BinaryWriter(stream);
                    for (int i = 0; i < 5; i++)
                    {
                        writer.Write(i);
                        Console.WriteLine("{0}位置写入流:{0}", i);
                    }
                }
                mutex.ReleaseMutex();
                Console.WriteLine("启动状态服务,按【回车】读取共享内存数据");
                Console.ReadLine();
                mutex.WaitOne();
                using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                {
                    var reader = new BinaryReader(stream);
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine("{1}位置:{0}", reader.ReadInt32(), i);
                    }
                }
                using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(1024, 10240))
                {
                    int colorSize = Marshal.SizeOf(typeof (ServiceMsg));
                    ServiceMsg color;
                    for (int i = 0; i < 50; i += colorSize)
                    {
                        accessor.Read(i, out color);
                        Console.WriteLine("{1}\tNowTime:{0}", new DateTime(color.NowTime), color.Id);
                    }
                }
                mutex.ReleaseMutex();
            }
            Console.WriteLine("测试: 我是 即时通讯 - 消息服务 我启动啦!!!");
            Console.ReadKey();
        }
    }
}

IMServer_State.exe代码

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Threading;
namespace IMServer_State
{
    /// <summary>
    /// 用于共享内存方式通信的 值类型 结构体
    /// </summary>
    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    }
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.Write("请输入共享内存公用名(默认:testmap):");
            string shareName = Console.ReadLine();
            if (string.IsNullOrEmpty(shareName))
                shareName = "testmap";
            using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(shareName, 1024000,MemoryMappedFileAccess.ReadWrite))
            {
                Mutex mutex = Mutex.OpenExisting("testmapmutex");
                mutex.WaitOne();
                using (MemoryMappedViewStream stream = mmf.CreateViewStream(20, 0)) //注意这里的偏移量
                {
                    var writer = new BinaryWriter(stream);
                    for (int i = 5; i < 10; i++)
                    {
                        writer.Write(i);
                        Console.WriteLine("{0}位置写入流:{0}", i);
                    }
                }
                using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(1024, 10240))
                {
                    int colorSize = Marshal.SizeOf(typeof (ServiceMsg));
                    var color = new ServiceMsg();
                    for (int i = 0; i < colorSize*5; i += colorSize)
                    {
                        color.Id = i;
                        color.NowTime = DateTime.Now.Ticks;
                        //accessor.Read(i, out color);
                        accessor.Write(i, ref color);
                        Console.WriteLine("{1}\tNowTime:{0}", new DateTime(color.NowTime), color.Id);
                        Thread.Sleep(1000);
                    }
                }
                Thread.Sleep(5000);
                mutex.ReleaseMutex();
            }
            Console.WriteLine("测试: 我是 即时通讯 - 状态服务 我启动啦!!!");
            Console.ReadKey();
        }
    }
}

以上就是C#.Net通信共享内存映射文件Memory Mapped的详细内容,更多关于C#.Net通信共享内存映射的资料请关注我们其它相关文章!

(0)

相关推荐

  • 一个进程间通讯同步的C#框架引荐

     0.背景简介 微软在 .NET 框架中提供了多种实用的线程同步手段,其中包括 monitor 类及 reader-writer锁.但跨进程的同步方法还是非常欠缺.另外,目前也没有方便的线程间及进程间传递消息的方法.例如C/S和SOA,又或者生产者/消费者模式中就常常需要传递消息.为此我编写了一个独立完整的框架,实现了跨线程和跨进程的同步和通讯.这框架内包含了信号量,信箱,内存映射文件,阻塞通道,及简单消息流控制器等组件.这篇文章里提到的类同属于一个开源的库项目(BSD许可),你可以从这里下载到

  • c# 通过内存映射实现文件共享内存的示例代码

    内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就像操作进程空间里的地址一样了,比如使用c语言的 memcpy等内存操作的函数.这种方法能够很好的应用在需要频繁处理一个文件或者是一个大文件的场合,这种方式处理IO效率比普通IO效率要高 共享内存是内存映射文件的一种特殊情况,内存映射的是一块内存,而非磁盘上的文件.共享内存的主语是进程(Process),操作系统默认会给每一 个进程分配一个内存空间,每一个进程只允许访问操作系统分配给它的哪一段内存,而不能访问其他进程

  • c# 如何实现不同进程之间的通信

    进程之间的通信是为了解决不同进程之间的数据传输问题,这样可以让不同程序交互数据.实现进程通信的方式:1.剪切板:2.COM:3.内存映射文件:4.WCF 1.剪切板Clipboard在进程间传送对象 剪切板是一个供应用程序使用的公有区域.在.NET中定一个了一个DataFormats类,此类包含一些静态字段,定义了剪切板中可以存放的数据类型.使用Clipboard类可以向剪切板中放入数据. 如将文字放入剪切板,使用方法SetDataObject即可:Clipboard.SetDataObject

  • c#进程之间对象传递方法

    1. 起源 KV项目下载底层重构升级决定采用独立进程进行Media下载处理,以能做到模块复用之目的,因此涉及到了独立进程间的数据传递问题. 目前进程间数据传递,多用WM_COPYDATA.共享dll.内存映射.Remoting等方式.相对来说,WM_COPYDATA方式更为简便,网上更到处是其使用方法. 而且Marshal这个静态类,其内置多种方法,可以很方便实现字符串.结构体等数据在不同进程间传递. 那么,对象呢?如何传递? 2.序列化 想到了,Newtonsoft.Json.dll这个神器.

  • C#.Net通信共享内存映射文件Memory Mapped

    目录 内存映射文件究竟是个什么? .Net 共享内存 内存映射文件原理 C# .Net 共享内存 演示代码 C# .Net 进程间通信共享内存 IMServer_Message.exe 代码 IMServer_State.exe代码 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当.实际上,任何想要共享数据的通信模型都会在幕后使用它

  • Python3 mmap内存映射文件示例解析

    1. mmap内存映射文件 建立一个文件的内存映射将使用操作系统虚拟内存来直接访问文件系统上的数据,而不是使用常规的I/O函数访问数据.内存映射通常可以提供I/O性能,因为使用内存映射是,不需要对每个访问都建立一个单独的系统调用,也不需要在缓冲区之间复制数据:实际上,内核和用户应用都能直接访问内存. 内存映射文件可以看作是可修改的字符串或类似文件的对象,这取决于具体的需要.映射文件支持一般的文件API方法,如close().flush().read().readline().seek().tel

  • Python使用mmap实现内存映射文件操作

    前言 内存映射通常可以提高I/O的性能,因为使用内存映射时,不需要对每个访问都建立一个单独的系统调用,也不需要在缓冲区之间复制数据,内核和用户都能很方便的直接访问内存. 说明 1)什么叫映射? ==>就是给一个对象(可以是变量.物理等),起一个唯一的别名,建立一一对应的关系: 2)文件映射:将磁盘上的文件的位置,与进程逻辑地址空间中一块大小相同的区域之间的一一对应: 3)映射后得到一个类似数组类型的东西(mmap.mmap()对象),可以通过类似操作数组的方式,达到对文件内容更改的目的: 优点

  • java 深入理解内存映射文件原理

    内存映射文件原理 首先说说这篇文章要解决什么问题? 1.虚拟内存与内存映射文件的区别与联系. 2.内存映射文件的原理. 3.内存映射文件的效率. 4.传统IO和内存映射效率对比. 虚拟内存与内存映射文件的区别与联系 二者的联系 虚拟内存和内存映射文件都是将一部分内容加载到,另一部分放在磁盘上的一种机制,二者都是应用程序动态性的基础,由于二者的虚拟性,对于用户都是透明的. 虚拟内存其实就是硬盘的一部分,是计算机RAM与硬盘的数据交换区,因为实际的物理内存可能远小于进程的地址空间,这就需要把内存中暂

  • Python内存映射文件读写方式

    我就废话不多说了,还是直接看代码吧! import os import time import mmap filename = 'test.txt' #如果不存在,创建. if not os.path.exists(filename): open(filename, 'w') print(os.path.isdir(filename)) if os.path.isfile(filename): print(time.ctime(os.path.getctime(filename))) fd =

  • java  深入理解内存映射文件原理

    内存映射文件原理 首先说说这篇文章要解决什么问题? 1.虚拟内存与内存映射文件的区别与联系. 2.内存映射文件的原理. 3.内存映射文件的效率. 4.传统IO和内存映射效率对比. 虚拟内存与内存映射文件的区别与联系 二者的联系 虚拟内存和内存映射文件都是将一部分内容加载到,另一部分放在磁盘上的一种机制,二者都是应用程序动态性的基础,由于二者的虚拟性,对于用户都是透明的. 虚拟内存其实就是硬盘的一部分,是计算机RAM与硬盘的数据交换区,因为实际的物理内存可能远小于进程的地址空间,这就需要把内存中暂

  • Go通道channel通过通信共享内存

    目录 引言 通道的声明与创建 接收 & 发送数据 引言 不要通过共享内存来通信 应该通过通信来共享内存 这句话有网友的解释如下: 这句俏皮话具体说来就是,不同的线程不共享内存不用锁,线程之间通讯用通道(channel)同步也用channel. chanel是协程之间传递信息的媒介,优雅地解决了某些后端开发常用语言中随处可见的lock,unlock,临界区等,把从很多线程层面解决的问题移到协程,从而静态地保证没有数据竞争. 通道的声明与创建 伪代码如下: //声明类型 var 通道名 chan 数

  • Java中使用内存映射实现大文件上传实例

    在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验. 复制代码 代码如下: package test; import java.io.BufferedInputStream;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import

  • C语言实现大数据文件的内存映射机制

    C语言实现大数据文件的内存映射机制 摘要 本文主要讲述大量数据的文件的内存映射机制的实现. 1. 内存映射 内存映射文件,是由一个文件到一块内存的映射.Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping).内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射.使用内存映射文件处理存储于磁盘上的文件时

  • Java中用内存映射处理大文件的实现代码

    在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验. package test; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOExc

随机推荐