【学习笔记】windows 下的 shared memory(共享内存)原理与实践

您所在的位置:网站首页 共享内存是怎么实现的 【学习笔记】windows 下的 shared memory(共享内存)原理与实践

【学习笔记】windows 下的 shared memory(共享内存)原理与实践

2024-07-14 14:12| 来源: 网络整理| 查看: 265

目录 先决条件共享内存介绍在 Win 下实现共享内存开发环境Process1CreateFileMappingMapViewOfFileUnmapViewOfFileCloseHandle Process2OpenFileMapping 示例补充File Mapping 参考

以下均用共享内存指代 shared memory

先决条件

你应该对以下内容有一定的了解

虚拟内存进程的基本概念什么是进程间通信 共享内存介绍

共享内存是一种进程间的通信机制,并且也是最底层的一种机制(其他的通信机制还有管道,消息队列等)。

进程之间通过访问一块共享的空间,来进行数据的通信(交换)。具体来讲,就是将一份物理内存映射到不同进程各自的虚拟地址空间,这样每个进程都可以读写这片相同的物理内存。

共享内存是速度最快的一种进程间通信(IPC)方式,它直接对内存进行存取,比操作系统提供的读写系统服务更快。

由上面的描述我们发现,当多个进程对同一片空间进行读写时必然会出现同步的问题,所以一般共享内存会和信号量或者锁机制一同使用,保证数据的一致性。 在这里插入图片描述

在 Win 下实现共享内存

共享内存在 Win 下通过 FileMapping 技术实现,关于 FileMapping 的介绍,建议先阅读补充部分,下面我们先来通过实际的代码感受一下效果。

首先,我们假设当下只有两个进程 P1,P2,并实现以下功能。

P1 进程负责创建共享空间,写入数据。P2 进程找到这个共享空间,读取数据。最终两个进程都关闭。

开发环境 os:window 10IDE:visual studio 2015 Process1

对于 P1 来说,它只需要实现以下几个函数,就可以完成上述流程。

CreateFileMappingMapViewOfFile写入数据的函数(自定义)UnmapViewOfFileCloseHandle

【注】对于这些函数更详细的解释,大家可以通过参考部分的链接寻找。

CreateFileMapping

为指定文件创建或打开命名或未命名文件映射对象。

// CreateFileMappingA 中 A 表示 ASCII 字符集,如果你的开发环境字符集是 Unicode,则使用 W 替换 A 作为结尾 // 或者直接使用 CreateFileMapping(它已经被定义成了宏)会自动根据你的项目中的字符集选择使用 A 还是 W HANDLE CreateFileMappingA( [in] HANDLE hFile, [in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes, [in] DWORD flProtect, [in] DWORD dwMaximumSizeHigh, [in] DWORD dwMaximumSizeLow, [in, optional] LPCSTR lpName );

参数解释

hFile:用于创建文件映射对象的文件句柄,将磁盘上的文件映射到物理内存地址空间中。但在实现共享内存时,我们不需要去拿硬盘中的文件,所以一般这个值填 INVALID_HANDLE_VALUE,表示共享未与文件关联的内存lpFileMappingAttributes:该参数决定返回的句柄是否可以被子进程继承,如果为 NULL,则不能。flProtect:指定文件映射对象的页面保护。对象的所有映射视图都必须与此保护兼容。当取 PAGE_READWRITE 时,表示对文件映射对象有可读可写的权限。dwMaximumSizeHigh:文件映射的最大长度的高32位。dwMaximumSizeLow:文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。lpName:给这个文件映射对象取一个名字。 返回值如果成功,则返回文件映射对象的句柄。如果失败则返回 NULL。

【注】[in] 表示传入的参数 【注】如果你对句柄和内核对象不太熟悉,可以阅读《Windows 核心编程》的相关章节 【注】不能映射长度为 0 的文件

MapViewOfFile

将文件映射对象映射进调用的进程的虚拟地址空间。

LPVOID MapViewOfFile( [in] HANDLE hFileMappingObject, [in] DWORD dwDesiredAccess, [in] DWORD dwFileOffsetHigh, [in] DWORD dwFileOffsetLow, [in] SIZE_T dwNumberOfBytesToMap );

参数解释

hFileMappingObject:填文件映射对象返回的句柄,即上面的函数或者 OpenFileMapping 的返回值。dwDesiredAccess:页面保护,用来控制接入文件映射对象的权限,其中 FILE_MAP_ALL_ACCESS 拥有读写权限。dwFileOffsetHigh:表示文件映射起始偏移的高32位。dwFileOffsetLow: 表示文件映射起始偏移的低32位。dwNumberOfBytesToMap :文件中要映射的字节数。为 0 表示映射整个文件映射对象,注意,它的单位是字节。 返回值如果函数成功,则返回值是映射视图的起始地址。否则返回 NULL。 UnmapViewOfFile

当完成对共享内存的操作后,你应该完成对应的关闭操作,第四步与第二步是对应的,即取消文件的视图映射。

取消文件映射后,进程中该部分的地址会被释放(你可以理解成 free 操作),然后该部分的内存可以被用于其他分配。

这里还要补充以下在关闭文件映射后,修改的内容并不会被立即写入磁盘中,首先它会等所有链接到文件映射对象的文件视图都关闭掉,然后即使都关闭掉,这些内容也可能缓存在内存中,以“懒惰”的方式写入磁盘。

下面来看看 UnmapViewOfFile 这个函数

BOOL UnmapViewOfFile( [in] LPCVOID lpBaseAddress );

参数解析

lpBaseAddress:指向要取消映射的文件视图,这是一个指针,这个值必须是前面调用的MapViewOfFile 或者 MapViewOfFileEx 函数的返回值。

返回值

如果函数成功,则返回非零值如果函数失败,则返回零值 CloseHandle

用于关闭打开的文件句柄。

BOOL CloseHandle( [in] HANDLE hObject );

参数解释

hObject:有效的打开了的句柄。 Process2

P2 中的函数的顺序和 P1 中大致一样,唯一的改变是,我们通过 P2 来打开(open)一个由 P1 创建好的文件映射对象。

OpenFileMappingMapViewOfFile读取数据的函数(自定义)UnmapViewOfFileCloseHandle OpenFileMapping

打开一个命名的文件映射对象。

HANDLE OpenFileMappingA( [in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] LPCSTR lpName );

参数解释

dwDesiredAccess:访问文件映射对象的权限,我们可以取 FILE_MAP_ALL_ACCESS,即可读可写。bInheritHandle:文件句柄能否被继承,为 TRUE 时可以被继承,反之不能。lpName:要打开的文件映射对象的名字。 示例

Process1

#include "stdafx.h" #include #include using namespace std; int main() { // 定义共享数据,在这里设置了一个 25MB 大小的数据用于模拟磁盘上的文件 long *lpBigData_A = (long *)malloc(sizeof(long) * BIG_BUF_SIZE); // 25 MB // 填充数据内容 for (long j = 0; j


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3