用文件映射(File Mapping)實現進程間內存共享

引用自:http://blog.csdn.net/starlee/archive/2007/06/01/1633762.aspx
  我們知道,在Windows中的每個進程都有自己獨立的內存空間。該獨立的內存空間包含了所有的可執行模塊或DLL模塊的代碼和數據以及動態內存分配的空間。每個進程的內存空間只能被該進程訪問,其他進程是不能訪問的。
    如果我們要想在進程間共享內存(也就是創建一塊不同進程都能訪問的內存),那就必須使用內核對象。因爲內核對象由Windows系統內核所擁有,而不是由進程所擁有。
    下面就用文件映射(File Mapping)和互斥量(Mutex)兩中內核對象來實現簡單的進程間內存共享。文件映射(File Mapping)用來開闢共享的內存空間,而互斥量(Mutex)則是用來使讀寫互斥。 Windows,實際上只有映像文件共享內存一種。
    在該例子裏,實現了下面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);    下面是函數的實現:
// 互斥量
CMutex g_mMutex(FALSE, "StarLeeMutex");

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, 0, sizeof(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, 0, 0, sizeof(UINT));

    if (pSize == NULL)
        return LX_INVALID_SHAREDMEMORY;

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

    UnmapViewOfFile(pSize);

    return LX_OK;
}

LX_RETURN_VALUE ReleaseSharedMemory()
{
    g_mMutex.Lock();

    // 打開共享內存
    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);

    g_mMutex.Unlock();

    return LX_OK;
}

LX_RETURN_VALUE GetSharedMemorySize(UINT& nSize)
{
    g_mMutex.Lock();

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

    if (hSize == NULL)
    {
        g_mMutex.Unlock();

        return LX_INVALID_SHAREDMEMORY;
    }

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

    if (pSize == NULL)
    {
        g_mMutex.Unlock();

        return LX_INVALID_SHAREDMEMORY;
    }

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

    g_mMutex.Unlock();

    return LX_OK;
}

LX_RETURN_VALUE WriteToSharedMemory(void *pDate, UINT nSize)
{
    g_mMutex.Lock();

    UINT nSharedMemorySize = 0;

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

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

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

    if (hFileMapping == NULL)
    {
        g_mMutex.Unlock();

        return LX_INVALID_SHAREDMEMORY;
    }

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

    if (pMapView == NULL)
    {
        g_mMutex.Unlock();

        return LX_INVALID_SHAREDMEMORY;
    }

    // 將數據寫入共享內存
    memcpy(pMapView, pDate, nSize);

    UnmapViewOfFile(pMapView);

    g_mMutex.Unlock();

    return LX_OK;
}

LX_RETURN_VALUE ReadFromSharedMemory(void *pData, UINT nSize)
{
    g_mMutex.Lock();

    UINT nSharedMemorySize = 0;

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

    if (nSize > nSharedMemorySize)
        return LX_INVALID_SIZE;

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

    if (hFileMapping == NULL)
    {
        g_mMutex.Unlock();

        return LX_INVALID_SHAREDMEMORY;
    }

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

    if (pMapView == NULL)
    {
        g_mMutex.Unlock();

        return LX_INVALID_SHAREDMEMORY;
    }   

    // 從共享內存讀取數據
    memcpy(pData, pMapView, nSize);

    UnmapViewOfFile(pMapView);

    g_mMutex.Unlock();

    return LX_OK;
}
用到的主要接口有:


The CreateFileMapping function creates or opens a named or unnamed file mapping object for the specified file.

HANDLE CreateFileMapping(  HANDLE hFile,  LPSECURITY_ATTRIBUTES lpAttributes,  DWORD flProtect,  DWORD dwMaximumSizeHigh,  DWORD dwMaximumSizeLow,  LPCTSTR lpName);The MapViewOfFile function maps a view of a file into the address space of the calling process.

To specify a suggested base address, use the MapViewOfFileEx function.

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


The OpenFileMapping function opens a named file mapping object.

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

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/ruixj/archive/2007/06/05/1639555.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章