zoukankan      html  css  js  c++  java
  • 用文件映射(File Mapping)实现进程间内存共享

    用到的几个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;
    }


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


  • 相关阅读:
    inotify和rsync实现数据实时同步
    Powershell在相应的文件夹下用管理员模式打开
    LOJ6498「雅礼集训 2018 Day2」农民
    LOJ6502「雅礼集训 2018 Day4」Divide
    LOJ6501「雅礼集训 2018 Day4」Cube
    2021-10-11 杂题选听
    LOJ6507 「雅礼集训 2018 Day7」A
    LOJ6497「雅礼集训 2018 Day1」图
    CF103E Buying Sets
    CF266D BerDonalds(图的绝对中心)
  • 原文地址:https://www.cnblogs.com/kex1n/p/2133389.html
Copyright © 2011-2022 走看看