内存映射文件原理

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

内存映射文件实现过程

HANDLE hFile = CreateFile(...);                              //创建文件对象
HANDLE hFileMapping = CreateFileMapping(hFile, ...); //创建文件映射对象
MapViewOfFile(hFileMapping, ...); //在虚拟地址空间上建立映射 //其他操作 UnmapViewOfFile(hFileMapping); //撤销在虚拟地址空间上的映射
CloseHandle(hFileMapping); //关闭文件映射对象句柄
CloseHandle(hFile); //关闭文件对象句柄

以上代码就是建立内存映射文件的基本思路,注意在MapViewOfFile()在虚拟地址空间上建立映射的时候磁盘中的文件并没有加载到内存中,只有当访问此虚拟地址空间时会往实际物理内存中寻找对应数据,如果没有就发生缺页中断从而让磁盘中的文件加载到物理内存中。

内存映射文件实现进程间通讯

以磁盘中的文件为物理存储器的内存映射文件

通过在多个不同的进程中使用同一个文件映射对象在各自的进程空间中建立映射。

使用写时复制

所谓的写时复制是指,当在虚拟地址空间上建立文件映射后,如果对此地址空间进行写操作时,其不直接更改对应在物理内存中的数据,而是将对应物理内存中的内存页复制到虚拟内存的页交换文件中,然后修改页交换文件的内容。(也就是不改变磁盘中的文件)

//进程A
HANDLE hFile = CreateFile(...);
HANDLE hFileMapping = CreateFileMapping(hFile, , PAGE_WRITECOPY, , , TEXT("MapFile")); //PAGE_WRITECOPY写时复制标志
LPVOID lpAddress = MapViewOfFile(hFileMapping, , FILE_MAP_COPY, ...); //FILE_MAP_COPY写时复制标志 UnmapViewOfFile(hFileMapping);
CloseHandle(hFileMapping);
CloseHandle(hFile); //进程B
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, TEXT("MapFile"));
LPVOID lpAddress = MapViewOfFile(hFileMapping, , FILE_MAP_COPY, ...); UnmapViewOfFile(hFileMapping);
CloseHandle(hFileMapping);

上述代码就是设置了写时复制标志,当进程A和进程B修改自己进程空间对应映射地址的内存时,其实际是会修改对应的(A修改A的,B修改B的)页面交换文件的数据,并没有修改对应的物理内存中的数据所以不能实现进程间通讯。

不使用写时复制

不使用写时复制也就是不使用PAGE_WRITECOPY和FILE_MAP_COPY标志,对地址空间进行写操作时,其直接更改对应在物理内存中的数据。因为在不同进程中是通过同一文件映射对象建立的映射,所以其修改的是同一物理内存,可以实现进程间通讯。

//进程A
HANDLE hFile = CreateFile(...);
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, TEXT("MapFile"));
LPVOID lpAddress = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); UnmapViewOfFile(hFileMapping);
CloseHandle(hFileMapping);
CloseHandle(hFile); //进程B
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, TEXT("MapFile")); //权限为FILE_MAP_ALL_ACCESS
LPVOID lpAddress = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); UnmapViewOfFile(hFileMapping);
CloseHandle(hFileMapping);

上述代码在没有使用写时复制标志,所以当A/B进程修改自己进程中的文件映射时实际就是在修改同一块物理内存的数据,可以实现进程间通讯。

同时注意:上述代码是利用给文件映射对象句柄命名从而跨进程使用句柄的,还可以使用句柄继承和句柄复制来实现跨进程共享句柄。

以页交换文件为物理存储器的内存映射文件

因为以磁盘中已存在的文件作为物理存储器的内存映射文件在实现进程间通讯时是通过更改文件中的数据通信的,结果是会使更改的数据保存到文件中。为了避免更改文件,Windows实现了利用虚拟内存的页交换文件为物理存储器的内存映射文件实现进程间通讯,其通过更改页交换文件实现通信,所以不会更改任何磁盘文件。

//进程A
HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, TEXT("MapFile"));
LPVOID lpAddress = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); UnmapViewOfFile(hFileMapping);
CloseHandle(hFileMapping); //进程B
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, TEXT("MapFile"));
LPVOID lpAddress = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); UnmapViewOfFile(hFileMapping);
CloseHandle(hFileMapping);

注意:CreateFileMapping第一个参数为INVALID_HANDLE_VALUE,其指定的内存映射文件的大小需要时1024的倍数。

Windows进程间通讯(IPC)----内存映射文件的更多相关文章

  1. QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开     本文地址:h ...

  2. High Performance Networking in Google Chrome 进程间通讯(IPC) 多进程资源加载

    小结: 1. 小文件存储于一个文件中: 在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里.其中有索引文件(在浏览器启动时加载到内存中),数据文件( ...

  3. Android AIDL 进行进程间通讯(IPC)

    编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...

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

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

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

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

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

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

  7. windows 进程间通讯方法

    Windows平台为我们提供了多种进程间通信的机制,主要包括:注册表方式.共享文件方式.共享内存方式.共享数据段.映射文件方式.管道方式. 剪贴板方式.消息方式.其中注册表方式需要增加注册表表项,而注 ...

  8. win32进程间通讯--共享内存

    小白一枚,如有不对,请各位大神多多指教! 最近看了看win32进程间通讯.简单写了写利用共享内存实现进程间通讯 使用共享内存实现进程间通讯: 1.在WM_CREATE消息下创建文件映射内核对象 hMa ...

  9. 服务 远程服务 AIDL 进程间通讯 IPC

    Activity aidl接口文件 package com.bqt.aidlservice;  interface IBinderInterface {     /* 更改文件后缀为[.aidl]去掉 ...

随机推荐

  1. 给Winform中的TabControl添加更现代的拖拽功能

    上周接到一个开发任务,大致是允许APP中的Tab拖动以成为一个独立Tab,脱离之前的TabControl,就是现在Web拖动标签页创建新窗口的功能,现在浏览器必备的功能,应该很简单,然而我司采用的Do ...

  2. 攻防世界 reverse EasyRE

    EasyRE 主函数 int sub_401080() { unsigned int lens; // kr00_4 signed int i; // edx char *v2; // esi cha ...

  3. LinkedList类详解

    LinkedList类中的方法与实现原理 目录 一.数据结构 二.类标题 三.字段 四.构造函数 五.方法分析 5.1 共有方法 public boolean add(Object o) public ...

  4. PAT (Advanced Level) Practice 1023 Have Fun with Numbers (20 分) 凌宸1642

    PAT (Advanced Level) Practice 1023 Have Fun with Numbers (20 分) 凌宸1642 题目描述: Notice that the number ...

  5. 你才不是只会理论的女同学-seata实践篇

    本文主要内容为seata的实践篇,理论知识不懂的请参考前文: 我还不懂什么是分布式事务 主要介绍两种最常用的TCC和AT模式. 环境信息: mysql:5.7.32 seata-server:1.4. ...

  6. IndentationError:unexpected indent”、“IndentationError:unindent does not match any outer indetation level”以及“IndentationError:expected an indented block Python常见错误

    错误的使用缩进量 记住缩进增加只用在以:结束的语句之后,而之后必须恢复到之前的缩进格式. 经典错误,一定要注意缩进,尤其是在非界面化下环境的代码修改

  7. Node.js 包管理器 NPM 讲解

    包管理器又称软件包管理系统,它是在电脑中自动安装.配制.卸载和升级软件包的工具组合,在各种系统软件和应用软件的安装管理中均有广泛应用.对于我们业务开发也很受益,相同的东西不必重复去造轮子. 每个工具或 ...

  8. Chrome89针对sessionStorage的更新导致数据共享问题

    最近将chrome更新到最新的版本,然后发现以前可以正常使用的功能无法使用了,经过分析后发现是浏览器新版本才出现的问题,今天记录以下. 一.遇到的问题 我们具体的问题场景,在A页面中需要打开B页面,同 ...

  9. 201871030127-王明强 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 18级卓越班 这个作业要求链接 实验三 软件工程结对项目 我的课程学习目标 1.熟悉PSP流程2. 熟悉github操作3.加深对D{0-1}问题的解法的理解4.熟悉ja ...

  10. (十)struts2的异常处理机制

    成熟的MVC框架应该提供成熟的异常处理机制.当然可以在方法中手动捕捉异常,当捕捉到特定异常时,返回特定逻辑视图名. 这种方式非常繁琐,需要在方法中写大量try catch块,最大的缺点还是一旦需要改变 ...