Windows共享内存解析

来源:互联网 发布:linux文件复制粘贴命令 编辑:程序博客网 时间:2024/06/05 07:32

在Windows程序开发过程中,当多个进程之间需要使用同样的数据的时候我们最好的方式就是通过共享内存进行处理(比如:当A进程运行时,进行数据处理,那么此时我想知道数据是不是正确,用B监控,那么A与B之间就可以使用共享内存的方式,并且这时来个C进程,他也可以访问这块共享内存数据进行监控)。
1.共享内存的原理
这里写图片描述
如图所示,尽管进程A和进程B在Windows下有两个相互独立的逻辑地址,但是在数据上,他们共用同一块内存区域,使得他们的数据保持一致。
2.Windows下的创建共享内存CreateFileMapping
MSDN中关于CreateFileMapping的定义

HANDLE WINAPI CreateFileMapping(  _In_     HANDLE                hFile,  _In_opt_ LPSECURITY_ATTRIBUTES lpAttributes,  _In_     DWORD                 flProtect,  _In_     DWORD                 dwMaximumSizeHigh,  _In_     DWORD                 dwMaximumSizeLow,  _In_opt_ LPCTSTR               lpName);

参数解释:

hFile

用于创建文件映射对象的文件的句柄。一般情况我们将这个参数设置为INVALID_HANDLE_VALUE,如果hFile设为INVALID_HANDLE_VALUE,调用进程还必须在dwMaximumSizeHighdwMaximumSizeLow参数中指定文件映射对象的大小。

lpAttributes

保护设置或者称为安全设置,我们一般设置为NULL,这样就是windows的默认安全设置。

flProtect

访问权限设置,通常有PAGE_READONLYPAGE_READWRITEPAGE_WRITECOPY,释义分别为只读,可读写,写时复制访问(留下备份)。

dwMaximumSizeHigh和dwMaximumSizeLow

高低位文件大小,当flProtect 设置为只读时,这样我们并不改变其大小,所以可以将这两个参数设置为0。否则我们将dwMaximumSizeHigh设置为0,dwMaximumSizeLow设置为我们想开辟的内存字节数。

lpName

共享文件内存的名称,一般比如我们开辟时设置为ShareMemoryTest,当我们访问时则也是访问这个名称ShareMemoryTest

3.将共享内存映射到进程的地址空间MapViewOfFile
MSDN中关于MapViewOfFile的定义

LPVOID WINAPI MapViewOfFile(  _In_ HANDLE hFileMappingObject,  _In_ DWORD  dwDesiredAccess,  _In_ DWORD  dwFileOffsetHigh,  _In_ DWORD  dwFileOffsetLow,  _In_ SIZE_T dwNumberOfBytesToMap);

参数解释:

hFileMappingObject

文件映射对象的句柄。接收CreateFileMappingOpenFileMapping函数返回该句柄。

dwDesiredAccess

访问文件映射对象的类型(权限)。要与在CreateFileMapping()时设置的访问权限相匹配。FILE_MAP_ALL_ACCESS等价于CreateFileMappingFILE_MAP_WRITE|FILE_MAP_READ. 文件映射对象被创建时必须指定PAGE_READWRITE选项.
FILE_MAP_COPY可以读取和写入文件.写入操作会导致系统为该页面创建一份副本.在调用CreateFileMapping时必须传入PAGE_WRITECOPY保护属性

dwFileOffsetHigh和dwFileOffsetLow

文件映射起始偏移的高32位和低32位,通常情况都设置为0。

dwNumberOfBytesToMap

指定需要映射的文件的字节数量,当dwNumberOfBytesToMap为0,则映射的是整个文件
返回值:当文件成功映射时则返回的值是映射到进程地址空间的首地址
4.打开共享内存OpenFileMapping()
MSDN中关于OpenFileMapping的定义

HANDLE WINAPI OpenFileMapping(  _In_ DWORD   dwDesiredAccess,  _In_ BOOL    bInheritHandle,  _In_ LPCTSTR lpName);

参数释义

dwDesiredAccess

MapViewOfFile中的dwDesiredAccess释义一样。

bInheritHandle

如果此参数为TRUE,CreateProcess函数创建的进程 可以继承该句柄; 否则,句柄不能被继承,一般情况下我们设置为FALSE。

lpName

要打开的文件映射对象的名称,也就是CreateFileMapping时的lpName。
5.代码示例
写端

#include <windows.h>#include <iostream>#include <string>#pragma warning(disable:4996)using namespace std;int main(){    string strMapName("ShareMemory");// 内存映射对象名称    string strData;//用于存储写入数据    LPVOID pBuffer;// 共享内存指针    HANDLE hMap;//定义一个句柄    getline(cin,strData);//读取一行数据给strData    hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,0,        strData.size(),        (LPCWSTR)strMapName.c_str());    pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);//得到与共享内存映射的指针    strcpy((char*)pBuffer, strData.c_str());//写入数据    cout << "写入共享内存数据:" << (char *)pBuffer << endl;    system("pause");    ::UnmapViewOfFile(pBuffer);//停止指针到共享内存的映射    ::CloseHandle(hMap);//关闭共享内存的句柄    return 0;}

读端

#include <windows.h>#include <iostream>#include <string>#pragma warning(disable:4996)using namespace std;int main(){    string strMapName("ShareMemory");// 内存映射对象名称    string strData;//用于存储共享内存中的数据    LPVOID pBuffer=NULL;// 共享内存指针                                                      HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, (LPCWSTR)strMapName.c_str());// 先判断要打开的共享内存名称是否存在    if (NULL == hMap)    {           cout << "尚未创建共享内存" << endl;    }    else    {    //共享内存存在,获得指向共享内存的指针,显示出数据        pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);        cout << "读取出共享内存数据:" << (char *)pBuffer << endl;    }    system("pause");    ::UnmapViewOfFile(pBuffer);    ::CloseHandle(hMap);    return 0;}
原创粉丝点击