进程间通信 - 动态链接库中共享内存(利用DLL的2~3G的地址段空间)
前言
进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据,以及其他的一些资源组成。32位系统的进程分配4G的虚拟地址空间。内存地址范围是0x00000000~0xFFFFFFFF。这个内存地址空间是每个进程独立的,也就是说,在一个进程中是不能访问其他进程的地址空间的。
举个例子,进程A的内存里保存了一个数据,假设这个数据的地址是0x33333333。这个是时候,即使把进程B的内存地址是0x33333333的数据读出来。这个数据也和进程A里同地址的数据是不一样的。甚至进程B的0x33333333地址根本就没有数据。
如果想要在多个进程间实现数据共享,这就涉及到进程间通信的问题了。当然,进程间的通信有很多种方法可以实现。比如,动态链接库,动态数据交换,文件映射,管道,剪切板等等。这篇文章主要讲讲利用动态链接库怎么实现进程间通信。
实现方法
动态链接库DLL是包含了一系列函数和数据的文件,它可以由应用程序调用其函数。
一般情况下,在应用程序调用一个dll里面的函数的时候,操作系统会将dll的文件映像映射到进程的地址空间中,这个时候dll对于进程中的线程来说只是一些被放在地址进程空间附加的代码和数据,当多个应用程序加载同一个dll的时候,dll在内存中只有一个。这个时候,如果其中一个进程调用DLL的函数,就会在当前进程的线程栈中取得传递给他的参数,并使用线程栈来存放他需要的变量。dll函数创建的任何对象都为调用线程或者调用进程拥有,dll不会拥有任何对象,也就是说如果dll中的一个函数调用了VirtualAlloc,系统会从调用进程的地址空间预定地址。在这种情况下是无法实现动态链接库的数据共享的。如果要想实现数据共享,首先我们来看看下面的进程虚拟空间构成图。
+---------------------------------+ 4 GB
| |
| 内核空间 |
| |
| |
+---------------------------------+ 3 GB
| |
| 用户共享空间 |
| |
| |
+---------------------------------+ 2 GB
| |
| 用户私有空间 |
| |
| |
+---------------------------------+ 0 GB
从这个图可以看出,上面所说的DLL的调用用的都是0GB-2GB的虚拟空间。想要实现共享的话,可以利用2GB-3GB的空间。也就是说,要把数据保存到这个空间里去。这里我们需要用#pragma data_seg()在DLL中定义一个共享的,有名字的数据段。具体怎么实现,我们可以通过下面这个示例来演示。
演示示例
首先创建一个共享DLL工程,这个DLL就是用来保存共享数据的。
实现步骤
1.新建一个Win32 Project,命名为SharedDll
2.程序类型选择DLL
3.工程结构
4.SharedDll.h文件,主要申明两个函数用来保存共享数据和取得共享数据。
- <span style="font-family:SimSun;font-size:14px;">// The following ifdef block is the standard way of creating macros which make exporting
- // from a DLL simpler. All files within this DLL are compiled with the SHAREDDLL_EXPORTS
- // symbol defined on the command line. this symbol should not be defined on any project
- // that uses this DLL. This way any other project whose source files include this file see
- // SHAREDDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
- // defined with this macro as being exported.
- #ifdef SHAREDDLL_EXPORTS
- #define SHAREDDLL_API __declspec(dllexport)
- #else
- #define SHAREDDLL_API __declspec(dllimport)
- #endif
- // This class is exported from the SharedDll.dll
- class SHAREDDLL_API CSharedDll {
- public:
- CSharedDll(void);
- // TODO: add your methods here.
- };
- // set string to shared dll
- SHAREDDLL_API void SetValueString(LPCSTR str);
- // get string from shared dll
- SHAREDDLL_API LPSTR GetValueString();
- </span>
5.SharedDll.cpp文件,用#pragma data_seg预处理指令用于设置共享数据段。
- <span style="font-family:SimSun;font-size:14px;">……
- //共享数据申明开始
- #pragma data_seg("SharedData")
- //一定要注意给下面的变量初始化,否则将无法实现数据在多个进程间共享
- char m_strString[256]="";
- //共享数据申明结束
- #pragma data_seg()
- //在连接器里定义共享数据段的权限为可读可写可共享
- #pragma comment(linker,"/SECTION:SharedData,RWS")
- // 共享数据的取得接口
- SHAREDDLL_API LPSTR GetValueString()
- {
- return m_strString;
- }
- // 共享数据的保存接口
- SHAREDDLL_API void SetValueString(LPCSTR str)
- {
- strcpy(m_strString,str);
- }
- ……
- </span>
到此为止,共享DLL的工程就做好了。接下来做两个MFC应用程序,用来保存数据到共享DLL,或者从共享DLL取得数据。
第一个程序:新建一个MCF的Dialog程序,画面如下。编辑框用来输入数据信息,[Submit]按钮用来提交数据到共享DLL。当然工程一定要导入SharedDLL的lib包。
实现代码如下:
- <span style="font-family:SimSun;font-size:14px;">……
- //[Submit]按钮的点击事件
- void CFormADlg::OnBnClickedOk()
- {
- //从编辑框控件取得输入的数据信息
- CEdit* e = (CEdit*) this->GetDlgItem(IDC_EDIT1);
- CString str;
- e->GetWindowText(str);
- //调用SharedDLL.dll的SetValueString接口保存数据到共享DLL
- SetValueString((LPCTSTR)str);
- }
- ……
- </span>
第二个程序:和上面的一样,新建一个MCF的Dialog程序,画面如下。编辑框用来显示数据信息,[Display]按钮用来取得共享DLL里保存的数据。这个工程同样需要导入SharedDLL的lib包。
代码如下:
- <span style="font-family:SimSun;font-size:14px;">……
- //[Display]按钮的点击事件
- void CFormBDlg::OnBnClickedOk()
- {
- //调用SharedDLL.dll的GetValueString接口取得共享数据
- CString str = (CString)GetValueString();
- //将取得的数据输出到FormB窗体的编辑框内
- CEdit* e = (CEdit*) this->GetDlgItem(IDC_EDIT1);
- e->SetWindowText(str);
- }
- </span>
这样所有的工程都完成了,接下来看看运行效果。
首先,我们把将 SharedDll.dll和FormA.exe和FormB.exe拷贝到同一目录下,方便它们互相访问。
而后运行FormA.exe和FormB.exe两个程序。
将数据信息输入FormA窗口的编辑框内,并且按下Submit按钮。
然后点击FormB窗口的Display按钮
从上面的这个示例可以看出,通过动态链接库能够实现了进程FormA和进程FormB之间的通信。
但是如果使用动态链接库进行进程间通讯需要注意一下几点。
1. 动态链接库的进程间通信是能适用于本地进程间通讯,不可用于跨网络间的通信。
2. 动态链接库的进程间通信是无法实现实时通知的问题。如果想要同时实现实时通知的问题,可以配合一些同步方法包括:Event, Mutex, 信号量Semaphore, 临界区资源等一起使用。
3. 想要用动态链接库的进程间通信,必须需要双方进程导入这个动态链接库。
具体怎么用,是否能用还需要具体情况具体对待。
http://blog.csdn.net/mickeyty/article/details/51721860
进程间通信 - 动态链接库中共享内存(利用DLL的2~3G的地址段空间)的更多相关文章
- 动态链接库中分配内存引起的问题-- windows已在XX.exe中触发一个断点
动态链接库中分配内存引起的 本文主要是探讨关于在动态链接库分配的内存在主程序中释放所产生的问题,该问题是我在刚做的PJP工程中所遇到的,由于刚碰到之时感动比较诡异(这也是学识不够所致),所以将它写下来 ...
- Linux 进程间通信(管道、共享内存、消息队列、信号量)
进程通信 : 不同进程之间传播或交换信息 为什么要进程通信呢? 协同运行,项目模块化 通信原理 : 给多个进程提供一个都能访问到的缓冲区. 根据使用场景,我们能划分为以下几种通信 ...
- nginx中共享内存的使用
在nginx的进程模型下,类似流量统计.流量控制.数据共享.等需要多个工作进程共同配合完成任务,共享内存是一个重要的进程通讯的方案.本文介绍在nginx的代码中与共享内存相关的功能,包括ngx_shm ...
- 进程间通信——IPC之共享内存
共享内存是三个IPC机制中的一个.它允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在进行的进程之间传递数据的一种非常有效的方式. 大多数的共享内存的实现,都把由不同进程之间共享 ...
- 进程间通信IPC之--共享内存
每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲 区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲 ...
- Linux进程间通信(System V) --- 共享内存
共享内存 IPC 原理 共享内存进程间通信机制主要用于实现进程间大量的数据传输,下图所示为进程间使用共享内存实现大量数据传输的示意图: 共享内存是在内存中单独开辟的一段内存空间,这段内存空间有自己特有 ...
- python学习笔记——多进程中共享内存Value & Array
1 共享内存 基本特点: (1)共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝. (2)为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将 ...
- 【Linux 应用编程】进程管理 - 进程间通信IPC之共享内存 mmap
IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...
- Linux进程间通信之《共享内存》入门
目录 简述 代码 写端代码 读取端代码 编译 运行 简述 共享内存是Linux系统进程间通信常用的方式,通常用于数据量较大的情况,如果只是用于不同的进程间消息通知,那不如用消息队列或者socket.之 ...
随机推荐
- C#生成二维码,把二维码图片放入Excel中
/// <summary> /// 把图片保存到excel中 /// </summary> /// <param name="excelFilePath&quo ...
- 【noip模拟】德充符
时间限制:2s 内存限制:512MB [题目描述] 申徒嘉和郑子产都是伯昏无人的学生,子产因为申徒嘉是残疾人,非常看不起他,于是想要刁难他. 子产给了申徒嘉 n个数 a1,a2...an. 现在他要求 ...
- 【hdu 2376】Average distance
[题目链接]:http://acm.hdu.edu.cn/showproblem.php?pid=2376 [题意] 让你计算树上任意两点之间的距离的和. [题解] 算出每条边的两端有多少个节点设为n ...
- Android Studio 报错Guest isn't online after 7 seconds 解决方案
最近使用真机模拟之后,再使用虚拟机就频繁出现这个问题; 解决步骤如下: 1.打开Android虚拟设备管理器, 2.查看Actoins栏下拉图标, 3.选择冷启动模式即可, 4.重启AVD正常;
- C# 直接创建多个类和使用反射创建类的性能
原文:C# 直接创建多个类和使用反射创建类的性能 本文告诉大家我对比的使用直接创建多个类和使用反射创建多个类的性能 在上一篇 C# 程序内的类数量对程序启动的影响 的基础上,继续做实验 现在创建 10 ...
- 浅谈Linux下各种压缩 解压命令和压缩比率对比
Linux下压缩.解压命令五花八门,不像在windows下一个winrar打遍天下无敌手,清一色的.rar .zip格式. 比如,Linux下常用的tar tar.gz tar.bz2 .Z等等不一而 ...
- Android实现图片滚动控件,含页签功能,让你的应用像淘宝一样炫起来
首先题外话,今天早上起床的时候,手滑一下把我的手机甩了出去,结果陪伴我两年半的摩托罗拉里程碑一代就这么安息了,于是我今天决定怒更一记,纪念我死去的爱机. 如果你是网购达人,你的手机上一定少不了淘宝客户 ...
- OpenGL(二十三) 各向异性纹理过滤
如果使用一般的纹理过滤,当观察方向跟模型表面不是相互垂直的的情况下,会出现纹理信息的丢失,表现为图像看上去比较模糊,如下图所示,远处场景的细节信息很差: 针对这种情况,可以采用同向异性过滤的方式处理纹 ...
- 脚本 启动/停止 jar包服务
windows (.bat): @set port=8692 @echo %port% for /f "tokens=5" %%i in ('netstat -aon ^| fin ...
- springboot使用logback日志,部署到tomcat不生效问题解决
1.springboot 配置日志方法 使用该方法配置日志,在本地调试可以正常写入日志文件,但是打包发布到tomcat以后日志配置不生效. 2.修改配置 Spring Boot官方推荐优先使用带有-s ...