精华内容
下载资源
问答
  • Windows共享内存解析

    千次阅读 2017-07-29 23:47:42
    Windows程序开发过程中,当多个进程之间需要使用同样的数据的时候我们最好的方式就是通过共享内存进行处理(比如:当A进程运行时,进行数据处理,那么此时我想知道数据是不是正确,用B监控,那么A与B之间就可以...

    在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;
    }
    展开全文
  • C++共享内存实现windows和linux)

    万次阅读 2018-08-27 16:13:13
    基本原理:以页面为单位,将一个普通文件映射到内存中,达到共享内存和节约内存的目的,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能 windows和linux都提供了原生的系统级的...

    共享内存是一种进程间通信的方式,速度比较快

    基本原理:以页面为单位,将一个普通文件映射到内存中,达到共享内存和节约内存的目的,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能

    windows和linux都提供了原生的系统级的C++接口,可以将文件映射到内存

    • windows中使用CreateFileMapping
    • linux使用mmap

    代码示例

    这里实现了两个进程,writer进程往共享内存里写数据,reader进程从共享内存里读数据

    main_writer.cpp

    #include <iostream>
    #include <string>
    #include <thread>
    #include <chrono>
    #ifdef _WIN32
    #include <windows.h>
    #elif __linux
    #include <string.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <unistd.h>
    #endif
    
    using namespace std;
    
    #ifdef _WIN32
    struct MyData
    {
        string name;
        int age;
        MyData(string _name, int _age) : name(_name), age(_age)
        {}
    };
    
    void writeMemory()
    {
        // define shared data
        char *shared_file_name = "my_shared_memory";
        unsigned long buff_size = 4096;
        char share_buffer[] = "greetings, hello world";
        //MyData share_buffer("Tom", 18);
    
        // create shared memory file
        HANDLE dump_file_descriptor = CreateFile(shared_file_name,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            OPEN_ALWAYS, // open exist or create new, overwrite file
            FILE_ATTRIBUTE_NORMAL,
            NULL);
    
        if (dump_file_descriptor == INVALID_HANDLE_VALUE)
            cout << "create file error" << endl;
    
        HANDLE shared_file_handler = CreateFileMapping(
            dump_file_descriptor, // Use paging file - shared memory
            NULL,                 // Default security attributes
            PAGE_READWRITE,       // Allow read and write access
            0,                    // High-order DWORD of file mapping max size
            buff_size,            // Low-order DWORD of file mapping max size
            shared_file_name);    // Name of the file mapping object
    
        if (shared_file_handler)
        {
            // map memory file view, get pointer to the shared memory
            LPVOID lp_base = MapViewOfFile(
                shared_file_handler,  // Handle of the map object
                FILE_MAP_ALL_ACCESS,  // Read and write access
                0,                    // High-order DWORD of the file offset
                0,                    // Low-order DWORD of the file offset
                buff_size);           // The number of bytes to map to view
    
    
    
            // copy data to shared memory
            memcpy(lp_base, &share_buffer, sizeof(share_buffer));
    
            FlushViewOfFile(lp_base, buff_size); // can choose save to file or not
    
            // process wait here for other task to read data
            cout << "already write to shared memory, wait ..." << endl;
            //cout << share_buffer << endl;
            this_thread::sleep_for(chrono::seconds(10));
    
            // close shared memory file
            UnmapViewOfFile(lp_base);
            CloseHandle(shared_file_handler);
            CloseHandle(dump_file_descriptor);
            //unlink(shared_file_name);
            cout << "shared memory closed" << endl;
        }
        else
            cout << "create mapping file error" << endl;
    }
    #elif __linux
    
    struct MyData
    {
        char name[20];
        int age;
    };
    
    void writeMemory()
    {
        // specify shared file path
        char *shared_file_name = "/home/user/codetest/my_shared_memory";
    
        // define shared data
        //    unsigned long buff_size = 4096;
        //    char share_buffer[] = "greetings, hello world";
        //    MyData share_buffer("Tom", 18);
        MyData share_buffer = { "Tom", 18 };
    
        // create mmap file
        int fd = open(shared_file_name, O_CREAT | O_RDWR | O_TRUNC, 00777);
        if (fd < 0)
            cout << "create file error" << endl;
    
        size_t write_size = sizeof(share_buffer);
    
        ftruncate(fd, write_size); // extend file size
    
        // map memory to file
        void *p = mmap(NULL, write_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    
        // copy data to shared memory
        memcpy(p, &share_buffer, write_size);
    
        cout << "already write to shared memory, wait ..." << endl;
        //cout << share_buffer << endl;
        this_thread::sleep_for(chrono::seconds(10));
    
        // unmap and close
        munmap(p, write_size);
        close(fd);
    
    }
    #endif
    
    int main()
    {
        writeMemory();
    
        return 0;
    }
    

    main_reader.cpp

    #include <iostream>
    #include <string>
    #ifdef _WIN32
    #include <windows.h>
    #elif __linux
    #include <string.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <unistd.h>
    #endif
    
    using namespace std;
    
    #ifdef _WIN32
    struct MyData
    {
        string name;
        int age;
        MyData(string _name, int _age) : name(_name), age(_age)
        {}
    };
    
    void readMemory()
    {
        char *shared_file_name = "my_shared_memory";
    
        // open shared memory file
        HANDLE shared_file_handler = OpenFileMapping(
            FILE_MAP_ALL_ACCESS,
            NULL,
            shared_file_name);
    
        if (shared_file_handler)
        {
            LPVOID lp_base = MapViewOfFile(
                shared_file_handler,
                FILE_MAP_ALL_ACCESS,
                0,
                0,
                0);
    
            // copy shared data from memory
            cout << "read shared data: " << endl;
            const unsigned long buff_size = 4096;
            //char share_buffer[buff_size] = { 0 };
            //strcpy(share_buffer, (char *)lp_base);
            char *share_buffer = (char *)lp_base;
    
            cout << share_buffer << endl;
    
            /*MyData *my_data = (MyData *)lp_base;
            cout << my_data->name << " " << my_data->age << endl;*/
    
            // close share memory file
            UnmapViewOfFile(lp_base);
            CloseHandle(shared_file_handler);
        }
        else
            cout << "open mapping file error" << endl;
    }
    #elif __linux
    struct MyData
    {
        char name[20];
        int age;
    };
    
    void readMemory()
    {
        // specify shared file path
        char *shared_file_name = "/home/user/codetest/my_shared_memory";
    
        // open mmap file
        int fd = open(shared_file_name, O_RDONLY, 00777);
        if (fd < 0)
            cout << "open file error" << endl;
    
        const unsigned long buff_size = 4096;
        //    size_t read_size = buff_size;
        size_t read_size = sizeof(MyData);
    
        // map file to memory
        void *p = mmap(NULL, read_size, PROT_READ, MAP_SHARED, fd, 0);
    
        cout << "read shared data: " << endl;
    
        //    char *share_buffer = (char *)p;
        //    cout << share_buffer << endl;
    
        MyData *share_buffer = (MyData *)p;
        cout << share_buffer->name << " " << share_buffer->age << endl;
    
        // unmap and close
        munmap(p, read_size);
        close(fd);
    }
    #endif
    
    int main()
    {
        readMemory();
    
        getchar();
    
        return 0;
    }
    

    注意:

    • 内存映射其实是将内存内容保存到了一个本地文件上,读写进程都操作这个文件映射对内存空间
    • windows中必须两个进程都开启,写进程可以不将文件落地,读进程其实只是读内存,linux的写和读进程可以分离,必须将文件落地,指向同一个文件路径
    • 可以传输复杂的结构体或者数组类型,需要计算好buffer的size,其中linux貌似杜宇string类型支持不好,改用char数组
    • 共享内存在实际使用中需要根据读写切换进行加锁保护
    • linux还有另外一种共享内存的方式,shm相关函数,这种方式读写速度更快,但是文件不落地,共享内存大小受限
    展开全文
  • 简单windows共享内存封装类

    千次阅读 2016-09-21 10:10:53
    简单windows共享内存封装类

    在维护公司的一个项目的时候发现了一个共享内存类,看了一下注释,发现是chrome里头的代码,所以就把chrome的代码翻出来看了一个,果然写的不错,考虑的情况也确实比较多,想想之前看过了《windows核心编程》这本书也有讲,所以就把书中的相关章节又看了一遍,写这篇文章就算是一个总结吧

    先上代码:

     

     

    #include <Windows.h>
    #include <string>
    #include <process.h>
    
    
    class SharedMemory
    {
    public:
        SharedMemory(BOOL bReadOnly = FALSE) : m_hLock(NULL),
            m_hFileMap(NULL),
            m_pMemory(NULL),
            m_bReadOnly(FALSE),
            m_dwMappedSize(0),
            m_strName(L"")
        {
        
        }
    
        BOOL Create(const std::wstring& strName, DWORD dwSize)
        {
            if (dwSize <= 0)
                return FALSE;
    
            HANDLE handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, dwSize, strName.empty() ? NULL : strName.c_str());
            if (!handle)
                return FALSE;
    
            // 已经存在了
            if (GetLastError() == ERROR_ALREADY_EXISTS)
            {
                Close();
                return FALSE;
            }
    
            m_hFileMap = handle;
            m_dwMappedSize = dwSize;
            return TRUE;
        }
    
        BOOL Open(const std::wstring& strName, BOOL bReadOnly)
        {
            m_hFileMap = ::OpenFileMappingW(bReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, FALSE, strName.empty() ? NULL : strName.c_str());
            if (!m_hFileMap)
                return FALSE;
    
            m_bReadOnly = bReadOnly;
            return TRUE;
        }
    
        BOOL MapAt(DWORD dwOffset, DWORD dwSize)
        {
            if (!m_hFileMap)
                return FALSE;
    
            if (dwSize > ULONG_MAX)
                return FALSE;
    
            ULARGE_INTEGER ui;
            ui.QuadPart = static_cast<ULONGLONG>(dwOffset);
    
            m_pMemory = ::MapViewOfFile(m_hFileMap,
                m_bReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, ui.HighPart, ui.LowPart, dwSize);
    
            return ( m_pMemory != NULL );
        }
    
        void Unmap()
        {
            if (m_pMemory)
            {
                ::UnmapViewOfFile(m_pMemory);
                m_pMemory = NULL;
            }
        }
    
        LPVOID GetMemory() const { return m_pMemory; }
    
        HANDLE GetHandle() const
        {
            return m_hFileMap;
        }
    
        // 锁定共享内存
        BOOL Lock(DWORD dwTime)
        {
            // 如果还没有创建锁就先创建一个
            if (!m_hLock)
            {
                std::wstring strLockName = m_strName;
                strLockName.append(L"_Lock");
                // 初始化的时候不被任何线程占用
                m_hLock = ::CreateMutexW(NULL, FALSE, strLockName.c_str());
                if (!m_hLock)
                    return FALSE;
            }
    
            // 哪个线程最先调用等待函数就最先占用这个互斥量
            DWORD dwRet = ::WaitForSingleObject(m_hLock, dwTime);
            return (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED);
        }
    
        void Unlock()
        {
            if (m_hLock)
            {
                ::ReleaseMutex(m_hLock);
            }
        }
    
        SharedMemory::~SharedMemory() 
        {
            Close();
            if (m_hLock != NULL)
            {
                CloseHandle(m_hLock);
            }
        }
    
        void Close()
        {
            Unmap();
    
            if (m_hFileMap)
            {
                ::CloseHandle(m_hFileMap);
                m_hFileMap = NULL;
            }
        }
    
    private:
        HANDLE m_hLock;
        HANDLE m_hFileMap;
        LPVOID m_pMemory;
        std::wstring m_strName;
        BOOL m_bReadOnly;
        DWORD m_dwMappedSize;
    
        SharedMemory(const SharedMemory& other);
        SharedMemory& operator = (const SharedMemory& other);
    };

     

     

     

     

     

    共享内存的原理:

    共享内存其实是一种特殊的文件映射对象,而文件映射对象本质上又是虚拟内存(这个知识点可以看《windows核心编程》或者在网上找资料了解学习一下)。

    虚拟内存一般是通过页交换文件来实现的,这个页交换文件是什么呢?一般就是我们C盘中的pagefile.sys文件,如下图所示:

     

     

    不过也有通过文件来实现的,比如我们双击exe文件,这时其实是用这个exe文件本身来作为虚拟内存来使用(参见《windows核心编程》中的讲解)。

    而内存映射文件实现原理也就是通过文件来实现虚拟内存的,实现原理和双击exe的原理是类似的。这个文件基本上可以是任意文件,打开之后作为虚拟内存映射到进程

    的地址空间中。

    我们先来大致看一下虚拟内存的使用过程吧:

    1. 在进程地址空间中预订区域(VirtualAlloc)

    2. 给区域调拨物理存储器(VirtualAlloc)

    3. 使用虚拟内存(memcpy等函数)

    4. 撤销调拨物理存储器,释放所预订的区域(VirtualFree)

    这里所说的物理存储器一般是指页交换文件(pagefile.sys)

     

    我们再来看一下内存映射文件的使用过程:

    1. 打开或者创建文件(CreateFile)

    2. 创建文件映射对象(CreateFileMapping)

    3. 映射文件视图(MapViewOfFile)

    4. 使用内存映射文件(memcpy等函数)

    5. 撤销文件视图(UnMapViewOfFile)

    6. 关闭映射文件句柄(CloseHandle)

     

    之前说内存映射文件本质上是虚拟内存,那么这两个过程又是怎么对应的呢?

    其实这两个过程基本上是一一对应的,只不过在上层使用的时候我们感觉不到而已。

    打开文件或创建文件可以看成是在准备虚拟内存的物理存储器。

    创建文件映射对象可以看成是预订区域

    映射文件试图可以看成是给区域调拨物理存储器,这个物理存储器就是之前打开或者创建的文件

    撤销文件视图可以看成是撤销调拨物理存储器

    关闭映射文件句柄可以看成是释放区域

    整个过程基本上就是这样。

     

    一个普通的文件映射对象的使用代码大致是这样子:

     

    HANDLE hFile = CreateFile(...)
    HANDLE hFileMap = CreateFileMapping(hFile, ...);
    PVOID pView = MapViewOfFile(hFileMap,FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
    memcpy(pView, ...);
    UnmapViewOfFile(pView);
    CloseHandle(hFileMap);
    CloseHandle(hFile);


    而共享内存的代码有什么不同呢?

     

    主要区别是物理存储器不一样,普通的内存映射文件都是使用磁盘上的文件作为物理存储器,而共享内存使用的是也交换文件(pagefile.sys)。

    这个区别如何体现的代码上呢?就是在调用函数CreateFileMapping的时候第一个参数是INVALID_HANDLE_VALUE。

    整个过程基本上讲解完了,下面来分析一下SharedMemory这个类。

     

    我们要在不同的进程中进行共享,那么我们需要创建一个命名的对象(其他进程间通信方式有:粘贴板,Socket,WM_COPY消息,邮槽,管道等)。

    还有一个问题是需要在不同线程之间进行同步,否则数据有可能会乱套。这里使用了一个互斥量。

    现在顺便问一个问题,能用关键段吗?

    不能,因为关键段不能跨进程使用,而且这种场合使用需要一个等待时间,关键段也是不支持的。

    至于关键段和互斥量的具体区别也可以参见《windows核心编程》里头的讲解。

    代码中的Lock函数会让第一个调用的线程占有互斥量,第二个调用者等待,用起来也是比较方便。

     

    代码应该不用过多解释吧,下面来一下使用示例:

     

     

    #include <Windows.h>
    #include <string>
    #include <process.h>
    #include <tchar.h>
    
    #define MAP_FILE_NAME (L"Global\\TestName")
    #define MAP_SIZE (4*1024)
    #define STRING_BUF (L"helloword")
    
    UINT __stdcall ThreadFunc(LPVOID lParam)
    {
        SharedMemory *pSharedMemory = NULL;
        pSharedMemory = new SharedMemory();
        pSharedMemory->Lock(INFINITE);
        pSharedMemory->Open(MAP_FILE_NAME, FALSE);
        pSharedMemory->MapAt(0, MAP_SIZE);
        LPVOID pVoid = pSharedMemory->GetMemory();
        int length = wcslen(STRING_BUF);
        WCHAR *pbuf = new WCHAR[length + 1];
        
        memcpy(pbuf, pVoid, length*2);
        pbuf[length] = L'\0';
    
        pSharedMemory->Unlock();
        pSharedMemory->Close();
        delete[] pbuf;
        delete pSharedMemory;
        int i = 0;
        while(true)
            Sleep(5000);
        return 1;
    }
    
    int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd )
    {
        SharedMemory *pSharedMemory = NULL;
        pSharedMemory = new SharedMemory();
        pSharedMemory->Lock(INFINITE);
        pSharedMemory->Create(MAP_FILE_NAME, MAP_SIZE);
        pSharedMemory->MapAt(0, MAP_SIZE);
        LPVOID pVoid = pSharedMemory->GetMemory();
        wcscpy((WCHAR*)pVoid, STRING_BUF);
        pSharedMemory->Unlock();
    
        _beginthreadex(NULL, 0, ThreadFunc, NULL, NULL, 0);
    
         Sleep(30000);
    
        delete pSharedMemory;
        
        return 0;
    }


    这里是在同一个进程的不同线程来测试的,用不同的进程也是没有问题的。

     

    每个线程在使用的时候一定要加锁解锁,否则就有可能出现数据不一致的问题。

    这个过程又一个很重要的问题,就是创建共享之后,不要调用Close函数把共享内存关闭了,这个过程在虚拟内存中相当于

    是否了申请的区域,如果这样的话其他进程就不能使用了,OpneFileMapping会失败,也就是不能共享数据了。

    之前发现OpenFileMapping失败了搞了半天才明白过来,看来之前对内存映射文件的理解还是不够深刻-_-

    注意,释放pSharedMemory的时候也调用了Close函数,所以要保证其他进程在通信过程中不要释放pSharedMemory指针。

     

    参考资料:

    1. 《windows核心编程》

    2. chrome源码中SharedMemory类的代码(在src\\base\\memory路径下)

    3. http://www.cnblogs.com/kex1n/archive/2011/08/10/2133389.html

     

     

    2020.5.1更新:

    评论区有些网友反映pVoid指针为空,那很可能是因为创建内存映射文件函数CreateFileMappingW调用失败了。

    因为在名称中我是这么写的:#define MAP_FILE_NAME (L"Global\\TestName")

    把全局命令空间前缀加上了,有些程序可能并没有权限去创建或者打开这样的内存映射文件导致。一般GetLastError会返回5,表示没有权限。解决办法可以把名称的Global\\去掉即可。

    展开全文
  • 共享内存原理:文件映射

    千次阅读 2018-08-26 18:53:23
    共享内存原理:文件映射 mmap()是将指定的文件利用虚拟内存技术映射到内存中去,在内存中建立页表项,但mmap()调用建立的页表项后面地址为空,只有使用到某个地址空间时才给此页面分配空间,要涉及到页面置换,...

    共享内存的原理:文件映射

    mmap()是将指定的文件利用虚拟内存技术映射到内存中去,在内存中建立页表项,但mmap()调用建立的页表项后面地址为空,只有使用到某个地址空间时才给此页面分配空间,要涉及到页面置换,因而需要有一定的物理内存做支撑,内存太小的话刚置入内存中的页面又要被交换到磁盘上,mmap的性能将大打折扣。

    mmap的优点主要在为用户程序随机的访问,操作,文件提供了一个方便的操作方法;其次就是为不同进程共享大批量数据提供高效的手段;另外就是对特大文件(无法一次性读入内存)的处理提供了一种有效的方法。

    文件映射的优点:

    先说结论:使用内存映射文件来处理大文件可以提高效率。 

    为什么呢?

    我们先来看看如果不使用内存映射文件的处理流程是怎样的,首先我们得先读出磁盘文件的内容到内存中,然后修改,最后回写到磁盘上。第一步读磁盘文件是要经过一次系统调用的,它首先将文件内容从磁盘拷贝到内核空间的一个缓冲区,然后再将这些数据拷贝到用户空间,实际上是两次数据拷贝。第三步回写也一样也要经过两次数据拷贝。

    所以我们基本上会有四次数据的拷贝了,因为大文件数据量很大,几十GB甚至更大,所以拷贝的开销是非常大的。

     

    而内存映射文件是操作系统的提供的一种机制,可以减少这种不必要的数据拷贝,从而提高效率。它由mmap()将文件直接映射到用户空间,mmap()并没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行了一次数据拷贝 ,比read进行两次数据拷贝要好上一倍,因此,内存映射的效率要比read/write效率高。

     

    一般来说,read write操作可以满足大多数文件操作的要求,但是对于某些特殊应用领域所需要的几十GB甚至更大的存储,这种通常的文件处理方法进行处理显然是行不通的。

    mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。

    当使用mmap映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用.但需注意,直接对该段内存写时不会写入超过当前文件大小的内容.

    采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。  

    展开全文
  • 共享内存,就是多个进程共用一块逻辑内存,每个进程均可对该内存进行读写,是实现进程间通信(本地通信)的一种方式。在Windows和linux平台均可实现实现流程相似,但调用的函数有所不同,这里只记录Windows平台下...
  • 利用共享内存实现进程间通信

    千次阅读 2015-06-20 15:50:59
    进程间通信的方法很多,共享内存便是其中的一种,其原理就是把一块物理内存,映射到两个不同进程的虚拟地址空间,这样一个进程对此快内存的操作就能被另一个进程看到。 windows下,使用共享内存有一下几个函数: ...
  • 共享内存的通信原理

    千次阅读 2018-09-29 10:34:56
    共享内存是System V版本的最后一个进程间通信方式。共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存...
  • Windows核心编程之共享内存

    千次阅读 2016-11-10 10:09:00
    Windows共享数据和信息的机制:RPC、COM、OLE、DDE、窗口消息、剪贴板、邮箱、管道、套接字以及内存映射文件。 内存映射:通过让两个或多个进程映射同一个文件。(在进程空间中保留一个地址空间区域,将物理存储器...
  • 利用共享内存实现消息队列

    千次阅读 2014-05-24 17:11:13
    利用共享内存实现消息队列  2009-02-28 22:02:44| 分类: Windows | 标签: |举报 |字号大中小 订阅  源代码下载 在Windows中没有方便操作Message Queue(消息队列)的API(在VxWorks中...
  • windows下利用文件映射实现共享内存

    千次阅读 2006-04-17 14:45:00
    windows下利用文件映射实现共享内存的办法比较简单,下面是实现代码,细节用注释说明.调用类似linux下shm的操作.该类没有进行太多的测试,欢迎提出问题和bug~~:)#include #include #include #include using ...
  • windows 内存原理与管理

    千次阅读 2017-02-14 17:01:50
    本文基本上是windows via c/c++上的内容,笔记做得不错。。 本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别...对Windows内存管理机制了解清楚,有效的利用C++内存函数管理和使用内存
  • Windows内存原理与内存管理

    千次阅读 2015-07-03 16:17:56
     Windows为每个进程分配了4GB的虚拟地址空间,让每个进程都认为自己拥有4GB的内存空间,4GB怎么来的? 32位 CPU可以取地址的空间为2的32次方,就是4GB.  当我们在Windows中双击一个应用程序图标后,系统为该...
  • 大家都知道进程之间的通信可以使用共享内存
  • Java内存模型与Java线程的实现原理

    万次阅读 2016-07-15 23:52:18
    Java内存模型与Java线程的实现原理
  • Windows进程间通信方法——共享内存

    千次阅读 2017-06-06 14:02:36
    1. 概述 Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊情况。...由于共享内存是用文件映射实现的,所以它也有较好的安全性,也只能运行于同一计算机上的进程之间。 2. 编码 2.1...
  • windows内核原理实现

    千次阅读 2018-02-03 17:16:57
    本文章是作者本人在学习《windows原理实现》一书时的一些总结和笔记 第二篇:windows系统总述 2.windows内核的基本概念  2.1处理器模式 intelx86处理器:0-最高级特权,cpu处在内核模式,可以访问当前...
  • Delphi如何实现内存共享

    千次阅读 2017-01-12 10:27:23
    一.原理  通过使用“内存映射文件”,... 共享内存结构:  PShareMem = ^TShareMem;  TShareMem = Record  id:string[10];  name:string[20];  age:Integer; end;  基本变量:  shareMemNa
  • Windows任务管理器原理+内存管理机密+揭穿内存优化工具的骗局原文:The Memory-Optimization Hoax:RAM optimizers make false promises 作者:Mark Russinovich 译者:盆盆 ...也许会经常看到一些弹出广告
  • 内存映射文件允许我们在WIN32进程的虚拟地址空间中保留一段内存区域,把目标文件映射到这段虚拟内存之中。我们可以用存取内存数据的方式直接操作文件中的数据,就好像这些数据放在内存中一样。而实际上,我们并没有...
  • c++中共享内存原理实现——三步走

    万次阅读 多人点赞 2018-06-08 16:37:27
    一、什么是共享内存 文件映射是一种实现进程间单向或双向通信的机制。它允许两个或多个本地进程间相互通信。为了共享文件或内存,所有的进程必须使用相同的文件映射的名字或是句柄。 二、实现步骤 为了实现共享...
  • 一、内存映射 内存映射文件允许开发人员预定一块地址空间区域并给区域调拨物理存储器。内存映射文件的物理存储器来自磁盘已有的文件,而不是来自系统的页交换文件。一旦把文件映射到地址空间,就可以对它进行访问,...
  • 共享内存使用方法

    千次阅读 2018-11-16 14:50:58
    大家都知道进程之间的通信可以使用共享内存,但是在具体代码中如何实现呢?下面就介绍下操作原理和我自己的实现代码。 在linux下使用的是shmget,shmat,shmdt等函数,所以在网上看到这类的,基本就是在介绍linux环境...
  • 一.原理  通过使用“内存映射文件”,... 共享内存结构:  PShareMem = ^TShareMem;  TShareMem = Record  id:string[10];  name:string[20];  age:Integer; end;  基本变量:  shareMemNa
  • IPC之Posix共享内存详解

    千次阅读 2016-01-12 00:22:53
     共享内存区,按标准可分为Posix共享内存区和System V共享内存区,两者在概念上类似。  Posix 表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX ),POSIX标准定义了操作系统应该为...
  • 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。  内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当。实际上,...
  • 摘要: 何为服务?Windows 会话中可长时间运行的可执行应用程序。...一个服务首先是一个Win32可执行程序,如果要写一个功能完备且强大的服务,需要熟悉动态连接库(DLL)、结构异常处理、内存映射文件、虚拟内存
  • C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。  内存映射文件对于托管世界的开发人员来说似乎很陌生,...
  • 共享Windows下C++库之内存池篇

    万次阅读 热门讨论 2010-08-17 17:42:00
    目录结构 内存池简介 介绍分析内存池改进及所使用技术 如何配合STL容器 性能测试 如何使用
  • Linux内存管理原理

    千次阅读 2018-02-22 23:04:24
    分页机制 分页机制是现代CPU实现内存寻址的一种机制(早期的intel芯片内存寻址实现机制有分段机制); 早期的CPU对内存的寻址是直接对物理内存(内存条)进行寻址,但这种在intel保护模式及现代CPU中已经很少使用,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,679
精华内容 25,471
关键字:

windows共享内存实现原理