C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

栏目: C# · 发布时间: 7年前

内容简介:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

节点通信存在两种模型:共享内存(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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A=B

A=B

Marko Petkovsek、Herbert S. Wilf、Doron Zeilberger / AK Peters, Ltd. / 1996-01 / USD 49.00

At some point, this book describes methods of solving the problem raised by Donald E. Knuth in the classical book "The Art of Computer Programming, Volume 1: Fundamental Algorithms". The main purpo......一起来看看 《A=B》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换