http://blog.codingnow.com/2005/10/interprocess_communications.html

Windows 下有很多方法实现进程间通讯,比如用 socket,管道(Pipe),信箱(Mailslot),等等。但最基本最直接的还是使用内存共享。其他方法最终还是会绕道这里。

可想而知,如果物理内存只有一份,让这份内存在不同的进程中,映射到各自的虚拟地址空间上,每个进程都可以读取同一份数据,是一种最高效的数据交换方法。下面我们就讨论如何实现它。

共享内存在 Windows 中是用 FileMapping 实现的。我们可以用 CreateFileMapping 创建一个内存文件映射对象, CreateFileMapping 这个 API 将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个实际的文件,所以,就不需要调用 CreateFile 创建一个文件, hFile 这个参数可以填写 INVALID_HANDLE_VALUE 。但是,文件长度是需要填的。Windows 支持长达 64bit 的文件,但是这里,我们的需求一定不会超过 4G , dwMaximumSizeHigh 一定是 0 ,长度填在 dwMaximumSizeLow 即可。然后调用 MapViewOfFile 映射到当前进程的虚拟地址上即可。一旦用完共享内存,再调用 UnmapViewOfFile 回收内存地址空间。

Windows 把 CreateFileMapping 和 MapViewOfFile 两个 API 分开做是有它的道理的。这是因为允许映射一个超过 4G 的文件,而地址空间最大只有 4G (实际上,一般用户的程序只能用到 2G) , MapViewOfFile 就可以指定文件的 Offset 而只映射一部分。

在 CreateFileMapping 的最后一个参数 pszName 填写一个名字,那么别的进程就可以用这个名字去调用 OpenFileMapping 来打开这个 FileMapping 对象,在新的进程内作映射。 不过,通过约定字符串的方法似乎不太优雅。

一个优雅的方法是,用 DuplicateHandle 在新进程中复制一份 FileMapping 对象出来,然后想办法把 Handle 通知新进程,比如用消息的方式传递过去。

如果需要共享内存的两个进程是父子关系,那么我们可以不用消息传递的方式来通知 FileMapping 的 Handle 。父进程可以用继承 Handle 的方式直接把 FileMapping 的 Handle 传递到子进程中。当然,在 CreateFileMapping 时就应该设置可以被继承的属性。

大约是这样:

SECURITY_ATTRIBUTES sa;
sa.nLength=sizeof(sa);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=TRUE;
handle=CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_READWRITE,0,size,NULL);

这样,在 CreateProcess 的时候,如果 bInheritHandles 参数为 TRUE ,所有有可被继承属性的内核对象都会被复制到子进程中。

注:内核对象的继承就是在 CreateProcess 创建子进程,但是子进程的主线程尚未活动之前,内核扫描当前进程中所有内核对象,检查出有可继承属性的那些,再用 DuplicateHandle 复制一份到子进程。由于是内核对象,在内核中实质只有一份,所有只是引用记数加一,父进程和子进程对同一内核对象的 Handle 一定是相同的。

复制内核对象的过程是由 CreateProcess 内部完成的,我们可以放心的把对象 Handle (和子进程相同) 通过命令行传递给子进程。或者,用环境变量传递也可以。

值得注意的是,子进程用完了这个 FileMapping 对象后一样需要 CloseHandle 减去引用计数。

备注:
CreateProcess 调用时,pszCommandLine 不能直接填上一个不可修改的字符串。例如:

CreateProcess("test.exe","test argument",...);

这样就是错误的,因为 "test argument" 会被编译器编译放到不可修改的数据段中。正确的方法是:

char cmdline[]="test argument";
CreateProcess("test.exe",cmdline,...);

这样,命令行的字符串就被放在堆栈上,是可以被读写的。

CreateProcess 的倒数第二个参数需要填写一个 STARTUPINFOW 结构,这个结构很复杂,通常填起来很麻烦。我们可以复制一份父进程的结构,再酌情修改。方法是:

STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
CreateProcess(...,&si,& pi);

这里, STARTUPINFO 结构的第一个长度信息通常应该填上,保证 GetStartupInfo(&si); 的正确执行。

[转]Windows 下的进程间通讯及数据共享的更多相关文章

  1. Windows进程间通讯(IPC)----消息队列

    消息队列 windows系统是通过消息驱动的,每移动一下鼠标,点击一下屏幕都会产生一个消息.这些消息会先被放在windows的一个系统消息队列(先进先出)中,windows系统会为每一个GUI线程创建 ...

  2. Windows进程间通讯(IPC)----共享内存

    Windows中同一个EXE文件多次加载过程 Windows中EXE文件加载是基于内存映射文件的. 当EXE文件第一次被加载. 首先系统会先创建一个进程内核对象,并创建一个新的进程地址空间. 系统调用 ...

  3. Windows进程间通讯(IPC)----内存映射文件

    内存映射文件原理 内存映射文件是通过在虚拟地址空间中预留一块区域,然后通过从磁盘中已存在的文件为其调度物理存储器,访问此虚拟内存空间就相当于访问此磁盘文件了. 内存映射文件实现过程 HANDLE hF ...

  4. Windows进程间通讯(IPC)----WM_COPYDATA

    WM_COPYDATA通讯思路 通过向其他进程的窗口过程发送WM_COPYDATA消息可以实现进程间通讯. 只能通过SendMessage发送WM_COPYDATA消息,而不能通过PostMessag ...

  5. .Net 利用消息在进程间通讯实现进程互操作

    有时候我们会遇到需要在两个进程间通过某种方式实现互操作,方法有很多,例如你可以尝试让两个进程持续监视一个外部文件,由此文件记录各自进程的数据:还有可以使用网络端口实现进程间通讯.共享一片内存区域记录及 ...

  6. Python 第八篇:异常处理、Socket语法、SocketServer实现多并发、进程和线程、线程锁、GIL、Event、信号量、进程间通讯

    本节内容: 异常处理.Socket语法.SocketServer实现多并发.进程和线程.线程锁.GIL.Event.信号量.进程间通讯.生产者消费者模型.队列Queue.multiprocess实例 ...

  7. 管道实现进程间通讯 、WaitNamedPipe

    一.管道实现进程间通讯 主要的理论知识 1.什么是管道以及分类 管道是两个头的东西,每一个头各连接一个进程或者同一个进程的不同代码,依照管道的类别分有两种管道,匿名的和命名的:依照管道的传输方向分也能 ...

  8. Node.js - 阿里Egg的多进程模型和进程间通讯

    前言 最近用Egg作为底层框架开发项目,好奇其多进程模型的管理实现,于是学习了解了一些东西,顺便记录下来.文章如有错误, 请轻喷 为什么需要多进程 伴随科技的发展, 现在的服务器基本上都是多核cpu的 ...

  9. C#进程间通讯或同步的框架引荐

    这篇文章主要介绍了一个进程间通讯同步的C#框架,代码具有相当的稳定性和可维护性,随着.NET的开源也会被注入更多活力,推荐!需要的朋友可以参考下  0.背景简介 微软在 .NET 框架中提供了多种实用 ...

随机推荐

  1. linux下crontab命令的使用

    1.crond crond是Linux下的一个守护进程,与windows下的计划任务类似,当操作系统安装完成后,默认会安装并启动进程,Linux下的任务调度分为两类,系统任务调度和用户任务调度. 系统 ...

  2. Shiro安全登录框架

    环境准备 本文使用Maven构建,因此需要一点Maven知识.首先准备环境依赖: <dependencies> <dependency> <groupId>juni ...

  3. BZOJ3669 (动态树)

    Problem 魔法森林 (NOI2014) 题目大意 给n个点,m条边的无向图,每条边有两个权值a,b. 求一条从1-->n的路径,使得这条路径上max(a)+max(b)最小.输出最小值即可 ...

  4. 安装go语言,配置环境及IDE,只需3步

    安装go语言,配置环境及IDE,只需3步 ( 欢迎加入go语言群: 218160862 , 群内有实践) 第1.下载 go压缩包,解压   ,如果你是window系统,请选择go1.5.windows ...

  5. 第三个Sprint冲刺第十天

    讨论地点:宿舍 讨论成员:邵家文.李新.朱浩龙.陈俊金 讨论问题:做最后的工作

  6. Professional.WebGL.Programming-Chapter 2(高级WebGL编程——第二章)

    (目前发现一些文章被盗用的情况,我们将在每篇文章前面添加原文地址,本文源地址:http://www.cnblogs.com/idealer3d/p/3508251.html) 这一章主要通过创建一个三 ...

  7. 学习maple

    定义函数:$f:=(x,y) \rightarrow x^2+y^2$ 类似mathematica的manipulate功能:plots[animate](plot,[f(x,y),x=0..1],y ...

  8. SPI机制

    Service Provider Interface 是java的服务提供的发现机制,很多框架中都有用到. 使用这个机制需要做以下几步: 1,在calsspath下见一个目录:META-INF\ser ...

  9. C++类和对象

    1.在类体中和类体外定义成员函数是有区别的:在类体中定义的成员函数为内联(inline)函数,在类体外定义的不是.内联函数一般不是我们所期望的,它会将函数调用处用函数体替代,所以我建议在类体内部对成员 ...

  10. [ADB]ADB(Android Debug Bridge)简介及基础(不包含命令)

    "Android Debug Bridge (adb) is a versatile command line tool that lets you communicate with an ...