学术咨询

让论文发表更省时、省事、省心

利用共享内存,实现进程间高效率数据共享

时间:2012年12月07日 分类:推荐论文 次数:

CPU速度比内存更快,内存中的缓存是用来解决CPU和内存速度差异的。多个模块都可以访问内存缓冲区,据此可以实用内存来实现进程间的数据共享。本文在Unix环境下实现该技术。

  摘要:CPU速度比内存更快,内存中的缓存是用来解决CPU和内存速度差异的。多个模块都可以访问内存缓冲区,据此可以实用内存来实现进程间的数据共享。本文在Unix环境下实现该技术。

  关键字:共享内存 多进程 文件映射

  Abstract: CPU speed faster than the memory, the cache memory is used to solve the CPU and memory speed differences. Multiple modules can access memory buffer, accordingly can realize between memories to practical process data sharing based on UNIX environment to realize this technology.

  Key Word: shared memory, processes, file mapping

  中图分类号:C37 文献标识码:A 文章编号:

  一、Windows系统中的共享内存的概念

  共享内存是在不同进程间可共享的内存块,是通过将同一块物理内存映射到不同进程地址空间中的方法,实现数据在内存中直接被不同进程共享。共享内存在几乎所有的操作系统中都存在,是进程间共享数据最高效的方法。

  在Windows操作系统中,共享内存是通过文件映射来使用。文件映射按共享方式可分为命名文件映射和非命名文件映射,按底层文件支持方式,又可分为有文件支持的文件映射和无文件支持的文件映射。

  命名文件映射指在创建文件映射时,为该文件映射提供一个名称,其它进程需要使用该文件映射时,通过该名称打开已经存在的文件映射。为文件映射起名时要注意,如果是在安装了终端服务器的服务器操作系统上,需要指定\\Global\或\\Local\名称前缀,指示是全局名称还是当前用户会话范围的名称。

  有底层文件支持的文件映射在创建文件映射时,为文件映射提供一个打开的文件句柄,该文件映射将对应使用提供的文件。文件映射创建的文件的一块区域或全部文件范围。文件映射的大小和文件本身的大小无关,如果文件的原始长度小于创建文件映射时指定的长度,Windows系统将首先将文件扩展到需要的长度,然后再创建文件映射。在文件映射被关闭后,共享内存中的数据会由操作系统自动保存到底层文件中,无需共享内存使用进程来处理数据的保存。当再次打开文件映射时,只需指定不要清除文件中的原有数据,即可直接使用上次进程关闭时所保存的数据。利用这个功能,可以很容易实现进程执行状态的保存。

  无底层文件支持的文件映射是在创建文件映射时,为该文件映射提供一个无效的文件句柄作为创建参数,同时提供文件映射的大小参数。Windows将在系统页面文件上,创建该文件映射。当文件映射被关闭时,共享内存中的数据将丢失。

  二、如何通过Windows Native API调用,使用共享内存

  使用共享内存的进程,需要完成以下步骤,来创建或打开共享内存:

  1) 利用CreateFile()函数打开底层支持文件。

  2) 使用CreateFileMapping()创建文件映射。如果创建文件映射成功,本函数将返回文件映射对象的句柄。如果同名的文件映射对象已经存在,本函数将返回该对象的句柄,使用GetLastError()将返回ERROR_ALREADY_EXISTS。当创建出错时,本函数将返回null,通过GetLastError()函数将返回错误代码。

  3) 使用MapViewOfFile()或MapViewOfFileEx()函数,将文件的一部分映射到进程的地址空间中。本函数将文件的一部分或全部映射到进程的地址空间中,函数返回共享内存的起始地址指针。

  对于后启动的进程,可以使用OpenFileMapping()函数来打开一个已知名称的文件映射,或使用继承得到或复制得到的句柄,直接使用文件映射对象。

  在使用共享内存的过程中,所有进程通过共享内存看到的文件相同部分的内容是一致的。但如果是通过文件读写来访问文件,看到文件相同部分,不保证是一致的。

  在使用完共享内存后,请使用UnmapViewOfFile()释放共享内存的映射。关闭同一个文件映射上的所有共享内存映射后,可使用CloseHandle()函数关闭文件映射对象和底层文件。所有使用共享内存对象的进程都关闭了共享内存对象后,共享内存对象才会被Windows系统释放。在释放共享内存对象的映射之前,使用CloseHandle()关闭函数文件映射对象,并不能释放共享内存对象和文件映射对象,只有该文件映射对象上的所有共享内存映射都被释放后,该文件映射对象才会被操作系统所释放。

  三、在C#中,通过封装Windows API,实现托管代码使用共享内存

  作为微软公司下一代的开发平台,.NET Framework近来成为Windows平台下程序开发人员的新宠,特别是C#语言,更是如日中天,但该平台并不能涵盖Windows开发的所有方面,特别是托管代码并不鼓励直接使用内存指针,这样,共享内存的使用在.NET Framework中并不被直接支持。

  要想使用共享内存在托管代码进程间高效共享数据,必须使用C#语言,自己封装Windows Native API,使用C#项目的非安全代码,并使用C#语言支持的指针操作。

  .NET Framework 4.0的发布,结束了这个痛苦的经历。.Net 4.0中,新增加了命名空间:System.IO.MemoryMappedFiles,该命名空间中,包括MemoryMappedFile,MemoryMappedFileSecurity,MemoryMappedViewAccessor,MemoryMappedViewStream 4个类。

  MemoryMappedFile类管理内存映像文件,其中CreateFromFile方法基于磁盘上的现有文件的指定路径或 FileStream创建一个内存映射文件。 未映射映射文件时,更改都将自动传播到磁盘。CreateNew方法创建一个未映射到磁盘上的现有文件的内存映射文件;而且这些方法还适合创建用于进程间通信 (IPC) 的共享内存。

  MemoryMappedFileSecurity表示可以针对内存映射文件授予的文件访问和操作权限。

  MemoryMappedViewAccessor类被用来访问可随机访问的内存映射文件视图,该类通过SafeBuffer类封装了映射到本地的非托管内存指针,并提供了大量的访问内存中内容的方法。本类使用CreateViewAccessor方法来获取此视图。

  MemoryMappedViewStream类将内存映射文件的视图表示为按顺序访问的流。使用 CreateViewStream对象的MemoryMappedFile方法来获取此流。

  以下是一个访问内存映像文件的主要代码片段,其中MyColor是一个自定义的结构类型:

  long offset = 0x10000000;long length = 0x20000000;

  using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data",

  FileMode.Open,"ImgA"))

  { using (var accessor = mmf.CreateViewAccessor(offset, length))

  { int colorSize = Marshal.SizeOf(typeof(MyColor));

  MyColor color;

  for (long i = 0; i < length; i += colorSize)

  { accessor.Read(i, out color);

  color.Brighten(10);

  accessor.Write(i, ref color);

  }

  }

  四、结束语

  经实际测试,共享内存相比其他几种方式有着更方便的数据控制能力,使用共享内存在处理大数据量数据的快速交换时表现出了良好的性能,在数据可靠性等方面要远远高于发送WM_COPYDATA消息的方式,数据在读写过程中会更透明。这种大容量、高速的数据共享处理方式在设计高速数传模块通讯类软件中有着很好的使用效果。