内存映射文件原理

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

内存映射文件实现过程

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. Python的web开发

    一.Web开发 Tcp   udp       Cs即客户端.服务器端编程,客户端和服务器端之间需要使用socket,约定协议.版本(协议使用的是tcp或者udp).Tcp协议和udp协议,指定地址和 ...

  2. Vue3手册译稿 - 深入组件 - 自定义事件

    本章节需要掌握组件基础 emit我译成发射,觉得发射这个词比较形象的形容将子组件事件发射出来的一个动作. 事件名 像组件和props,事件名也会进行自动转换,如果你在子组件里发射一个驼峰命名的事件,你 ...

  3. PTA 利用指针找最大值

    6-6 利用指针找最大值 (10 分)   本题要求实现一个简单函数,找出两个数中的最大值. 函数接口定义: void findmax( int *px, int *py, int *pmax ); ...

  4. Docker上安装Redis

    Docker可以很方便的进行服务部署和管理,下面我们通过docker来搭建Redis的单机模式.Redis主从复制.Redis哨兵模式.Redis-Cluster模式 一.在Docker上安装单机版R ...

  5. SQL排名问题,100% leetcode答案大公开!

    (首先原谅我最近新番看多了,起了一个中二的名字) 最近在找实习,所以打算系统总结(复习)一下sql中经常遇到问题.不管是刷leetcode还是牛客的sql题,有一个问题总是绕不开的,那就是排名问题.其 ...

  6. Oracle 19c Data Guard DML Redirection ADG备库上执行DML重定向(未来更好的进行读写分离)

    资料来自官方网站: https://docs.oracle.com/en/database/oracle/oracle-database/19/sbydb/managing-oracle-data-g ...

  7. [BFS]最小转弯问题

    最小转弯问题 Description 给出一张地图,这张地图被分为 n×m(n,m<=100)个方块,任何一个方块不是平地就是高山.平地可以通过,高山则不能.现在你处在地图的(x1,y1)这块平 ...

  8. spring-cloud-gateway 服务网关

    Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关.网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发.权限校验.限流控制等 ...

  9. 透视HTTP协议,带你拨开纷繁复杂的表象

    一个HTTP,打趴80%面试者! HTTP是一个在计算机世界里专门在两点之间传输文字.图片.音频.视频等超文本数据的约定和规范.如果你不懂HTTP协议,那就相当于是个只有半桶水的程序员. 在这个专栏中 ...

  10. 记一次在virtualbox中安装windows7遇到增强功能安装分辨率的问题

    在windows7中遇到很多次安装好增强功能后并不能对其实现放大分辨率,使其跟随虚拟机界面大小而改变. 经过许多次的安装和恢复快照,发现了在设置中,显存的大小一直都是处于边缘的状态, 关闭虚拟机后,我 ...