享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信。因为是通过内存操作实现通信,因此是一种最高效的数据交换方法。

共享内存在 Windows 中是用 FileMapping 实现的,从具体的实现方法上看主要通过以下几步来实现:

1、调用 CreateFileMapping 创建一个内存文件映射对象;

HANDLE CreateFileMapping(
HANDLE hFile, // handle to file to map
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
// optional security attributes
DWORD flProtect, // protection for mapping object
DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
DWORD dwMaximumSizeLow, // low-order 32 bits of object size
LPCTSTR lpName // name of file-mapping object
);

通过这个API函数 将创建一个内存映射文件的内核对象,用于映射文件到内存。与虚拟内存一样,内存映射文件可以用来保留一个地址空间的区域,并将物理存储器提交
给该区域。它们之间的差别是,物理存储器来自一个已经位于磁盘上的文件,而不是系统的页文件。

hFile:用于标识你想要映射到进程地址空间中的文件句柄。该句柄可以通过调用C r e a t e F i l e函数返回。这里,我们并不需要一个实际的文件,所以,就不需要调用 CreateFile 创建一个文件, hFile 这个参数可以填写 INVALID_HANDLE_VALUE; 

lpFileMappingAttributes:参数是指向文件映射内核对象的 SECURITY_ATTRIBUTES结构的指针,通常传递的值是 N U L L;

flProtect:对内存映射文件的安全设置(PAGE_READONLY 以只读方式打开映射;PAGE_READWRITE 以可读、可写方式打开映射;PAGE_WRITECOPY 为写操作留下备份)

dwMaximumSizeHigh:文件映射的最大长度的高32位。

dwMaximumSizeLow:文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。

lpName:指定文件映射对象的名字,别的进程就可以用这个名字去调用 OpenFileMapping 来打开这个 FileMapping 对象。
 
如果创建成功,返回创建的内存映射文件的句柄,如果已经存在,则也返回其句柄,但是调用 GetLastError()返回的错误码是:183(ERROR_ALREADY_EXISTS),如果创建失败,则返回NULL;

2、调用 MapViewOfFile 映射到当前进程的虚拟地址上;

如果调用CreateFileMapping成功,则调用MapViewOfFile函数,将内存映射文件映射到进程的虚拟地址中;

LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // file-mapping object to map into
// address space
DWORD dwDesiredAccess, // access mode
DWORD dwFileOffsetHigh, // high-order 32 bits of file offset
DWORD dwFileOffsetLow, // low-order 32 bits of file offset
DWORD dwNumberOfBytesToMap // number of bytes to map
);
 
hFileMappingObject:CreateFileMapping()返回的文件映像对象句柄。
dwDesiredAccess: 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。
dwFileOffsetHigh: 表示文件映射起始偏移的高32位.
dwFileOffsetLow: 表示文件映射起始偏移的低32位.
dwNumberOfBytesToMap :文件中要映射的字节数。为0表示映射整个文件映射对象。

3、在接收进程中打开对应的内存映射对象

在数据接收进程中,首先调用OpenFileMapping()函数打开一个命名的文件映射内核对象,得到相应的文件映射内核对象句柄hFileMapping;如果打开成功,则调用MapViewOfFile()函数映射对象的一个视图,将文件映射内核对象hFileMapping映射到当前应用程序的进程地址,进行读取操作。(当然,这里如果用CreateFileMapping也是可以获取对应的句柄)

HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // access mode
BOOL bInheritHandle, // inherit flag
LPCTSTR lpName // pointer to name of file-mapping object
);
 
dwDesiredAccess:同MapViewOfFile函数的dwDesiredAccess参数
bInheritHandle :如这个函数返回的句柄能由当前进程启动的新进程继承,则这个参数为TRUE。

lpName :指定要打开的文件映射对象名称。

4、进行内存映射文件的读写

一旦MapViewOfFile调用成功,就可以像读写本进程地址空间的内存区一样,进行内存的读写操作了。

//读操作:

// 打开成功,映射对象的一个视图,得到指向共享内存的指针,显示出里面的数据
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pBuffer)
{
cout << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
//cout << "读取共享内存数据:" << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
}
else
{
cout << "打开共享数据失败!" << endl;
}

//写操作:

// 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pBuffer)
{
memcpy((CThostFtdcDepthMarketDataField*)pBuffer, DepthMarketData, sizeof(CThostFtdcDepthMarketDataField));
//cout << "写入共享内存数据:" << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
}
else
{
cout << "打开共享数据失败!" << endl;
}

5、清理内核对象

在用完后,要取消本进程地址空间的映射,并释放内存映射对象。

    //取消本进程地址空间的映射;
UnmapViewOfFile(pLocalMem); pLocalMem=NULL;
//关闭文件映射内核文件
CloseHandle(hFileMapping);

Windows进程通信 -- 共享内存的更多相关文章

  1. Windows进程通信 -- 共享内存(1)

    共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 W ...

  2. Windows进程通信-共享内存空间

    三个模块 1,game.exe,三个方法,控制台输入指令('A','B','R')分别控制三个方法的调用: 2,WGDll.dll,要注入到game进程中的dll文件: 3,myconsole.exe ...

  3. Windows进程间共享内存通信实例

    Windows进程间共享内存通信实例 抄抄补补整出来 采用内存映射文件实现WIN32进程间的通讯:Windows中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们在WIN32进程中保 ...

  4. Linux学习笔记(14)-进程通信|共享内存

    在Linux中,共享内存是允许两个不相关的进程访问同一个逻辑内存的进程间通信方法,是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式. 不同进程之间共享的内存通常安排为同一段物理内存.进程可 ...

  5. Windows中利用共享内存来实现不同进程间的通信

    Windows中利用共享内存来实现不同进程间的通信 一.msdn详细介绍 https://docs.microsoft.com/zh-cn/windows/win32/memory/sharing-f ...

  6. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案

    C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...

  7. linux 两个进程通过 共享内存 通信例子

    例子1:两个进程通过共享内存通信,一个进程向共享内存中写入数据,另一个进程从共享内存中读出数据 文件1 创建进程1,实现功能,打印共享内存中的数据 #include <stdio.h> # ...

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

    原文:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing ...

  9. 【VS开发】内存映射文件进程间共享内存

    内存映射文件进程间共享内存 内存映射文件的另一个功能是在进程间共享数据,它提供了不同进程共享内存的一个有效且简单的方法.后面的许多例子都要用到共享内存.共享内存主要是通过映射机制实现的.Windows ...

随机推荐

  1. NBUT 1220 SPY

    $map$,简单模拟. #include<cstdio> #include<cstring> #include<cmath> #include<algorit ...

  2. ExtJs基础

    方法和属性 Ext.caeate方法相当于创建一个实例对象 renderTo:Ext.getBody()  新创建的组件渲染到什么位置 grid.render('grid-example'); /re ...

  3. 07.C#中如何排除/过滤/清空/删除掉字符串数组中的空字符串

    方式一:使用lambda表达式筛选过滤掉数组中空字符串         1 /// <summary> /// 使用lambda表达式排除/过滤/清空/删除掉字符串数组中的空字符串 /// ...

  4. 【BZOJ 1052】 1052: [HAOI2007]覆盖问题 (乱搞)

    1052: [HAOI2007]覆盖问题 Description 某人在山上种了N棵小树苗.冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄 膜把这些小树遮盖起来,经过一番长久的 ...

  5. 关于lower_bound的优先级重载

    今天才知道$lower\_bound$最后有一个优先级参数…… 首先$lower\_bound$中的优先级和序列优先级必须相同才有效 $lower\_bound$中优先级默认的是小于号,也就是说仅当序 ...

  6. 计算标准差 Exercise07_11

    import java.util.Scanner; /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:计算标准差 * */ public class Exercise07_11 ...

  7. PHP与mysql数据库

    1.PHP访问数据库的一般步骤 连接MySQL服务器 选择MySQL数据库 执行SQL语句(增,删,改,查) 关闭结果集,释放资源 关闭MySQL服务器的连接 需要查的表的数据: 2.连接和关闭实例 ...

  8. svn: None of the environment variables SVN_EDITOR...问题解决

    转:http://blog.163.com/lgh_2002/blog/static/44017526201046111856208/ 问题1: svn: Could not use external ...

  9. 【JSTL】<c:if test=“”>没有else的解决方法

    后台封装了一个对象 放在model里: model.addAttribute("notice", notice); notice是个对象 然后前台如果没有公告的话,希望显示暂无公告 ...

  10. js禁止复制粘贴

    1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键,其实是禁止快捷菜单,因为不光右键可以弹出这个菜单,键盘上空格 ...