9.1.7 使用共享数据段实现进程间的通信的技巧
1.问题阐述
进程间的数据交换和共享是一种非常重要和实用的技术。大、中型软件的开发设计多是由众多程序设计人员合作完成的,通常一个程序设计人员只负责其中一个或几个模块的开发,这些模块可以是动态链接库也可以是应用程序或其他形式的程序组件。这些独立开发出来的程序模块最终需要作为一个整体来运行,即组成一个系统,在系统运行期间这些模块往往需要频繁地进行数据交换和数据共享,对于动态链接库同其主应用程序之间的数据交换是非常容易实现的,但是在两个应用程序之间或动态链接库同其主调应用程序之外的其他应用程序进行数据交换就比较困难了。尤其是在交换数据量过大、交换过于频繁的情况下更是难以实现,本文即对此展开讨论,并提出了一种通过共享内存来实现进程间大数据量快速交换的一种方法。
2.实现技巧
在Windows操作系统下,任何一个进程不允许读取、写入或修改另一个进程的数据(包括变量、对象和内存分配等),但是在某个进程内创建的文件映射对象的视图却能够为多个其他进程所映射,这些进程共享的是物理存储器的同一个页面。因此,当一个进程将数据写入此共享文件映射对象的视图时,其他进程可以立即获取数据变更情况。为了进一步提高数据交换的速度,还可以采用由系统页文件支持的内存映射文件而直接在内存区域使用,显然这种共享内存的方式是完全可以满足在进程间进行大数据量数据快速传输任务要求的。下面给出在两个相互独立的进程间通过文件映射对象来分配和访问同一个共享内存块的应用实例。在本例中,由发送方程序负责向接收方程序发送数据,文件映射对象由发送方创建和关闭,并且指定一个唯一的名字供接收程序使用。接收方程序直接通过这个唯一指定的名字打开此文件映射对象,并完成对数据的接收。
在发送方程序中,首先通过CreateFileMapping()函数创建一个内存映射文件对象,如果创建成功则通过MapViewOfFile()函数将此文件映射对象的视图映射进地址空间,同时得到此映射视图的首地址。可见,共享内存的创建主要是通过这两个函数完成的,这两个函数原型声明如下:
HANDLE CreateFileMapping(HANDLE hFile, |
CreateFileMapping()函数的参数hFile指定了待映射到进程地址空间的文件句柄,如果为无效句柄则系统会创建一个使用来自页文件而非指定磁盘文件存储器的文件映射对象。很显然,在本例中为了使数据能快速交换,需要人为将此参数设定为INVALID_HANDLE_VALUE;参数flProtect设定了系统对页面采取的保护属性,由于需要进行读写操作,因此可以设置保护属性PAGE_READWRITE;双字型参数dwMaximumSizeHigh和dwMaximumSizeLow指定了所开辟共享内存区的最大字节数;最后的参数lpName用来给此共享内存设定一个名字,接收程序可以通过这个名字将其打开。MapViewOfFile()函数的参数hFileMappingObject为CreateFileMapping()返回的内存文件映像对象句柄;参数dwDesiredAccess再次指定对其数据的访问方式,而且需要同CreateFileMapping()函数所设置的保护属性相匹配。这里对保护属性的重复设置可以确保应用程序能更多地对数据的保护属性进行有效控制。
3.实例代码
下面给出创建共享内存的部分关键代码:
hRecvMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | |
// 数据复制到共享内存 |
HWND hDeCode = ::FindWindow(NULL, DECODE_PROGRAMM); |
m_hReceiveMap = OpenFileMapping(FILE_MAP_READ, FALSE, "DataMap"); |
memcpy(RecvBuf, (char*)(m_lpbReceiveBuf), (int)lParam); |
4.小结
经实际测试,使用共享内存在处理大数据量数据的快速交换时表现出了良好的性能,在数据可靠性等方面要远远高于发送WM_COPYDATA消息的方式。这种大容量、高速的数据共享处理方式在设计高速通信类软件中有着很好的使用效果。
| 回书目 上一节 下一节 |