用文件映射(File Mapping)实现进程间内存共享

摘要:
LpFileMappingAttributes是文件共享的属性。DwMaximumSizeHigh是文件共享大小的上字节。HFileMappingObject是一个共享文件对象。DwFileOffsetHigh是文件共享的偏移地址。DwNumberOfBytesToMap是共享数据的长度。打开现有的命名文件映射。函数原型如下:HANDLEOpenFileMapping;参数:dwDesiredAccess:输入参数,Mapping对象的访问权限,请参见CreateFileMapping函数的flProtect参数。如果返回NULL,则表示失败。接下来,我们使用两个内核对象,文件映射和互斥,来实现简单的进程间内存共享。在进程中加载DLL并调用相应的函数,实现进程间内存共享。

用到的几个windows API函数:

函数CreateFileMapping、MapViewOfFile声明如下: 
WINBASEAPI 
__out 
HANDLE 
WINAPI 
CreateFileMappingA( 
     __in      HANDLE hFile, 
     __in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes, 
     __in      DWORD flProtect, 
     __in      DWORD dwMaximumSizeHigh, 
     __in      DWORD dwMaximumSizeLow, 
     __in_opt LPCSTR lpName 
     ); 
WINBASEAPI 
__out 
HANDLE 
WINAPI 
CreateFileMappingW( 
     __in      HANDLE hFile, 
     __in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes, 
     __in      DWORD flProtect, 
     __in      DWORD dwMaximumSizeHigh, 
     __in      DWORD dwMaximumSizeLow, 
     __in_opt LPCWSTR lpName 
     ); 
#ifdef UNICODE 
#define CreateFileMapping CreateFileMappingW 
#else 
#define CreateFileMapping CreateFileMappingA 
#endif // !UNICODE 
   
WINBASEAPI 
__out 
LPVOID 
WINAPI 
MapViewOfFile( 
     __in HANDLE hFileMappingObject, 
     __in DWORD dwDesiredAccess, 
     __in DWORD dwFileOffsetHigh, 
     __in DWORD dwFileOffsetLow, 
     __in SIZE_T dwNumberOfBytesToMap 
     ); 
hFile是创建共享文件的句柄。 
lpFileMappingAttributes是文件共享的属性。 
flProtect是当文件映射时读写文件的属性。 
dwMaximumSizeHigh是文件共享的大小高位字节。 
dwMaximumSizeLow是文件共享的大小低位字节。 
lpName是共享文件对象名称。 
hFileMappingObject是共享文件对象。 
dwDesiredAccess是文件共享属性。 
dwFileOffsetHigh是文件共享区的偏移地址。 
dwFileOffsetLow是文件共享区的偏移地址。 
dwNumberOfBytesToMap是共享数据长度。 


打开已经存在的命名的文件映射,函数原型如下:
HANDLE OpenFileMapping(

    DWORD    dwDesiredAccess,

    BOOL        bInheritHandle,

    LPCTSTR  lpName);

    参数:

dwDesiredAccess: 输入参数,Mapping对象的存取权限,参见CreateFileMapping函数的flProtect参数。

bInheritHandle: 输入参数,如果设置为TRUE,则可继承进程句柄,否则不能继承。一般设置为FALSE。

返回值:

返回HANDLE值,Mapping对象的句柄。如果返回NULL,则表示失败。可使用GetLastError函数获取错误信息。

 取消文件映射,函数原型如下:

    BOOL UnmapViewOfFile(

        LPCVOID lpBaseAddress);

    参数lpBaseAddress为需要取消映射的内存地址。

    返回值:

    返回值BOOL,表示是否成功。

/**********************************************************************************************************************************/

我们知道,在Windows中的每个进程都有自己独立的内存空间。该独立的内存空间包含了所有的可执行模块或DLL模块的代码和数据以及动态内存分配的空间。每个进程的内存空间只能被该进程访问,其他进程是不能访问的。
    如果我们要想在进程间共享内存(也就是创建一块不同进程都能访问的内存),那就必须使用内核对象。因为内核对象由Windows系统内核所拥有,而不是由进程所拥有。
    下面就用文件映射(File Mapping)和互斥量(Mutex)两中内核对象来实现简单的进程间内存共享。文件映射(File Mapping)用来开辟共享的内存空间,而互斥量(Mutex)则是用来使读写互斥。
    在该例子里,实现了下面5个函数用来进行进程间的内存共享。可以把这5个函数放到一个DLL里面当成输出函数来用。在进程里加载该DLL并调用相应的函数就可实现进程间内存共享。
    首先,定义返回值代码:

typedef enum
{
    LX_OK                                
= 0// 正常返回
    LX_SHAREDMEMORY_EXISTS  = 1// 共享内存已经存在
    LX_INVALID_SHAREDMEMORY = 2// 共享内存错误返回
    LX_INVALID_SIZE                 = 3  // 共享内存大小错误
}LX_RETURN_VALUE;

    然后,是函数声明:

// 创建共享内存
LX_RETURN_VALUE CreateSharedMemory(UINT nSize);
// 释放共享内存
LX_RETURN_VALUE ReleaseSharedMemory();
// 得到共享内存大小
LX_RETURN_VALUE GetSharedMemorySize(UINT& nSize);
// 向共享内存写入数据
LX_RETURN_VALUE WriteToSharedMemory(void *pData, UINT nSize);
// 从共享内存读取数据
LX_RETURN_VALUE ReadFromSharedMemory(void *pData, UINT nSize);

    下面是函数的实现:

// 自动Lock和Unlock互斥量
struct CAutoMutex
{
    CAutoMutex();
    
~CAutoMutex();

    
// 互斥量
    static CMutex m_mutex;
};

CMutex CAutoMutex::m_mutex(FALSE, 
"StarLeeMutex");

CAutoMutex::CAutoMutex()
{
    m_mutex.Lock();
}

CAutoMutex::
~CAutoMutex()
{
    m_mutex.Unlock();
}

LX_RETURN_VALUE CreateSharedMemory(UINT nSize)
{
    
// 创建共享内存块
    HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, nSize, "StarLeeSharedMemory");

    
// 创建错误
    if ((hFileMapping == NULL) || (hFileMapping == INVALID_HANDLE_VALUE))
        
return LX_INVALID_SHAREDMEMORY;

    
// 共享内存已经存在
    if (GetLastError() == ERROR_ALREADY_EXISTS)
        
return LX_SHAREDMEMORY_EXISTS;

    
// 创建另外一块内存存放共享内存的大小
    HANDLE hSize = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0sizeof(UINT), "StarLeeSharedMemorySize");

    
if ((hSize == NULL) || (hSize == INVALID_HANDLE_VALUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
        
return LX_INVALID_SHAREDMEMORY;

    
// 得到存放共享内存大小的指针
    UINT *pSize = (UINT *)MapViewOfFile(hSize, FILE_MAP_WRITE, 00sizeof(UINT));

    
if (pSize == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    
// 写入共享内存的大小
    memcpy(pSize, &nSize, sizeof(UINT));

    UnmapViewOfFile(pSize);

    
return LX_OK;
}

LX_RETURN_VALUE ReleaseSharedMemory()
{
    CAutoMutex MutexLock;

    
// 打开共享内存
    HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "StarLeeSharedMemory");

    
// 关闭共享内存
    if (hFileMapping != NULL)
        CloseHandle(hFileMapping);

    
// 打开存放共享内存大小的文件映射
    HANDLE hSize = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "StarLeeSharedMemorySize");

    
// 关闭存放共享内存大小的文件映射
    if (hSize != NULL)
        CloseHandle(hSize);

    
return LX_OK;
}

LX_RETURN_VALUE GetSharedMemorySize(UINT
& nSize)
{
    CAutoMutex MutexLock;

    HANDLE hSize 
= OpenFileMapping(FILE_MAP_READ, FALSE, "StarLeeSharedMemorySize");

    
if (hSize == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    UINT 
*pSize = (UINT *)MapViewOfFile(hSize, FILE_MAP_READ, 00sizeof(UINT));

    
if (pSize == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    
// 得到共享内存的大小
    memcpy(&nSize, pSize, sizeof(UINT));

    
return LX_OK;
}

LX_RETURN_VALUE WriteToSharedMemory(
void *pDate, UINT nSize)
{
    UINT nSharedMemorySize 
= 0;

    
// 得到共享内存的大小
    if (GetSharedMemorySize(nSharedMemorySize) != LX_OK)
        
return LX_INVALID_SHAREDMEMORY;

    
// 检查共享内存的大小
    if (nSize > nSharedMemorySize)
        
return LX_INVALID_SIZE;

    CAutoMutex MutexLock;

    HANDLE hFileMapping 
= OpenFileMapping(FILE_MAP_WRITE, FALSE, "StarLeeSharedMemory");

    
if (hFileMapping == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    
void *pMapView = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 00, nSize);

    
if (pMapView == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    
// 清空共享内存
    memset(pMapView, 0, nSharedMemorySize);

    
// 将数据写入共享内存
    memcpy(pMapView, pDate, nSize);

    UnmapViewOfFile(pMapView);

    
return LX_OK;
}

LX_RETURN_VALUE ReadFromSharedMemory(
void *pData, UINT nSize)
{
    UINT nSharedMemorySize 
= 0;

    
if (GetSharedMemorySize(nSharedMemorySize) != LX_OK)
        
return LX_INVALID_SHAREDMEMORY;

    
if (nSize > nSharedMemorySize)
        
return LX_INVALID_SIZE;

    CAutoMutex MutexLock;

    HANDLE hFileMapping 
= OpenFileMapping(FILE_MAP_READ, FALSE, "StarLeeSharedMemory");

    
if (hFileMapping == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    
void *pMapView = MapViewOfFile(hFileMapping, FILE_MAP_READ, 00, nSize);

    
if (pMapView == NULL)
        
return LX_INVALID_SHAREDMEMORY;

    
// 从共享内存读取数据
    memcpy(pData, pMapView, nSize);

    UnmapViewOfFile(pMapView);

    
return LX_OK;
}


最后附记:栈是每个线程都有的,堆则是每个进程有的。


免责声明:文章转载自《用文件映射(File Mapping)实现进程间内存共享》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Oracle获取alter.log的方法idea之常用设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Windows消息机制详解

消息是指什么? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。 消息本身是作为一个记录传递给应用程序的,这个记录中包含...

DMA映射 dma_addr_t

DMA映射 一个DMA映射是要分配的DMA缓冲区与为该缓冲区生成的、设备可访问地址的组合。 DMA映射建立了一个新的结构类型——dma_addr_t来表示总线地址。dma_addr_t类型的变量对驱动程序是不透明的, 唯一允许的操作是将它们传递给DMA支持例程以及设备本身。 根据DMA缓冲区期望保留的时间长短,PCI代码有两种DMA映射: 1) 一致性映射...

文件共享服务,FTP,NFS,SAMBA配置

文件共享服务 一、NFS (Network File System) 网络文件系统 它的主要功能是通过网络让不同的机器系统之间可以彼此共享文件和目录。NFS服务器可以允许NFS客户端将远端NFS服务器端的共享目录挂载到本地的NFS客户端中。在本地的NFS客户端的机器看来,NFS服务器端共享的目录就好像自己的磁盘分区和目录一样。一般客户端挂载到本地目录的名字...

Android深入浅出之 AudioTrack分析

Android深入浅出之Audio 第一部分 AudioTrack分析 一 目的 本文的目的是通过从Audio系统来分析Android的代码,包括Android自定义的那套机制和一些常见类的使用,比如Thread,MemoryBase等。 分析的流程是: l         先从API层对应的某个类开始,用户层先要有一个简单的使用流程。 l        ...

共享内存与存储映射(mmap)

【前言】对这两个理解还是不够深刻,写一篇博客来记录一下。 首先关于共享内存的链接:共享内存。里面包含了创建共享内存区域的函数,以及两个进程怎么挂载共享内存通信,分离、释放共享内存。 共享内存的好处就是效率高,不需要太多次的进行数据的copy。可以直接进行读写内存。所以,相对来说在IPC进程间通信三大主题里面,共享内存要比消息队列使用多,而且消息队列只在有血...

MUD教程--巫师入门教程3

1. 指令格式为:edit <档名>,只加文件名,默认为当前目录,加here,表示编辑你当前所处的房间, 回车后即进入线上编辑系统。2. 如果这是一个已经有的档案,你可以使用 z 或 Z 来看档案。z表示一次显示20行,Z表示一次显示40行。为了编辑方便,最好在开始时用 n 表示每一行在开头处显示它的行数,再用一次 n 取消行数显示;3. 还有...