美文网首页
共享内存

共享内存

作者: 古典小说 | 来源:发表于2019-07-11 09:56 被阅读0次

    一 进程逻辑空间    物理空间

    如上图所示,每个进程都有自己的逻辑空间,这些逻辑空间,会被映射到具体的物理空间中。

    每个进程的逻辑空间都是彼此隔离,相互独立不受干扰的。

    但是他们都会被映射到同一个物理空间去,当其所映射的物理空间有重叠的时,这重叠的部分就共享了物理内存

    二 共享内存关键问题

    创建物理内存

    将物理内存映射到进程空间

    读写互斥控制

    1)创建物理内存,获得物理内存资源句柄

    比如     由A进程 负责创建共享内存

    A: 进程创建完物理内存后,直接返回物理内存句柄

        // 创建共享文件句柄

        HANDLE hMapFile = CreateFileMapping(

            INVALID_HANDLE_VALUE,  // 物理文件句柄

            NULL,  // 默认安全级别

            PAGE_READWRITE,  // 可读可写

            0,  // 高位文件大小

            BUF_SIZE,  // 地位文件大小

            L"ShareMemory"  // 共享内存名称

            );

    B:B进程通过共享内存的全局名字,来获得共享物理内存句柄

        // 打开共享的文件对象

        HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,L"ShareMemory");

    2) 物理内存映射进程空间

        各个进程都是通过这种方式, 将物理空间共享内存,映射到进程逻辑空间

        // 映射缓存区视图 , 得到指向共享内存的指针

        LPVOID lpBase = MapViewOfFile(

            hMapFile,            // 共享内存的句柄

            FILE_MAP_ALL_ACCESS, // 可读写许可

            0,

            0,

            BUF_SIZE

            );

    3) 释放

    进程退出时,要解除映射

    // 解除文件映射

    UnmapViewOfFile(lpBase);

    // 关闭内存映射文件对象句柄

    CloseHandle(hMapFile);

    4)互斥控制

      采用互斥量或信号的机制

     互斥量机制

    进程A:

        创建互斥量mutex

        while(1)

        {

            申请mutex;

            处理C;

            释放mutex;

            其他操作;

        }

    进程B:

        while(1)

        {

            申请mutex;

            处理C;

            释放mutex;

            其他操作;

        }

    示例:

    进程A

    #include <iostream>

    #include <windows.h>

    using namespace std;

    int main()

    {

    // 若不存在名为"pmutex"的互斥量则创建它;否则获取其句柄

        HANDLE hMutex = CreateMutex(NULL, false, "pmutex");

        if(NULL == hMutex)

        {

            cout<<"create mutex error "<<GetLastError()<<endl;

            return 0;

        }

        else

        {

            cout<<" create mutex success:"<<hMutex<<endl;

        }

        for(int i = 0;i<10; i++)

        {

    // 申请对互斥量的占有

            DWORD  d  = WaitForSingleObject(hMutex, INFINITE);

            if(WAIT_OBJECT_0 == d)

            {

    // 模拟对公共内存/文件的操作

                cout<<"begin sleep"<<endl;

                Sleep(2000);

                cout<<"process 1"<<endl;

    // 操作完毕,释放对互斥量的占有

                if(ReleaseMutex(hMutex)!=0)

                {

                    cout<<"reslease ok"<<endl;

                }

                else

                {

                    cout<<"reslease failed"<<endl;

                }

            }

            if(WAIT_ABANDONED == d)

            {

                cout<<"WAIT_ABANDONED"<<endl;

            }

            if(WAIT_FAILED ==d)

            {

                cout<<"mutex error"<<endl;

            }

            Sleep(2000);

        }

    // 释放互斥量

        CloseHandle(hMutex);

    hMutex = NULL;

        return 0;

    }

    进程B

    #include <iostream>

    #include <windows.h>

    using namespace std;

    int main()

    {

    // 若不存在名为"pmutex"的互斥量则创建它;否则获取其句柄

        HANDLE hMutex = CreateMutex(NULL, false, "pmutex");

        if(NULL == hMutex)

        {

            cout<<"create mutex error "<<GetLastError()<<endl;

            return 0;

        }

        else

        {

            cout<<" create mutex success:"<<hMutex<<endl;

        }

        for(int i = 0;i<10; i++)

        {

    // 申请对互斥量的占有

            DWORD  d  = WaitForSingleObject(hMutex, INFINITE);

            if(WAIT_OBJECT_0 == d)

            {

    // 模拟对公共内存/文件的操作

                cout<<"begin sleep"<<endl;

                Sleep(2000);

                cout<<"process 2"<<endl;

    // 操作完毕,释放对互斥量的占有

                if(ReleaseMutex(hMutex)!=0)

                {

                    cout<<"reslease ok"<<endl;

                }

                else

                {

                    cout<<"reslease failed"<<endl;

                }

            }

            if(WAIT_ABANDONED == d)

            {

                cout<<"WAIT_ABANDONED"<<endl;

            }

            if(WAIT_FAILED ==d)

            {

                cout<<"mutex error"<<endl;

            }

            Sleep(2000);

        }

    // 释放互斥量

      // CloseHandle(hMutex); 互斥量的申请和释放应该由一个进程单独完成 此处有A完成,否则可能会堵塞

    hMutex = NULL;

        return 0;

    }

    信号量机制:

      进程A : 执行 写操作

    进程A 执行写操作

    //等待其他进程读操作完毕

    WaitForSingleObject(m_memMng.m_hReadEvent, INFINITE); 

    //重置写操作信号量

    ResetEvent(m_memMng.m_hWriteEvent);

    //执行写操作

    memcpy

    //写操作完毕,恢复信号量,使得其它进程可读

    SetEvent(m_memMng.m_hWriteEvent);

    进程B: 执行读操作

    //进程B执行读操作

    //等待主进程写完毕

    WaitForSingleObject(m_memMng.m_hWriteEvent, INFINITE);

    //重置读信号量

    ResetEvent(m_memMng.m_hReadEvent);

    //读操作,将共享内存数据拷贝本地变量

    memcpy

    //读操作完毕,设置信号量信号

    SetEvent(m_memMng.m_hReadEvent);

    三 封装

    应该有的成员变量:

    1)创建物理内存、映射进程空间 管理

    HANDLE hMapping_;  物理空间资源句柄

    MappedView View_;    物理映射成进程空间的操作

    int size_;                       物理空间大小

    std::wstring name_;       共享内存名字

    2) 信号量控制管理

       HANDLE m_hReadEvent;

       HANDLE m_hWriteEvent;

    操作方法:

    1)创建

                bool CreateFileMap();                            //创建

                bool OpenFileMap();                               //已存在,则打开

                bool MapView(bool bCanWrite = true);   //映射进程空间

    2)映射管理类

    class MappedView

    {

    public:

    MappedView() : view_(NULL) {}

    ~MappedView() { CloseView(); }

    bool MapView(SharedMemory *shared_memory, bool can_write);//MapViewOfFile

    void CloseView();

    char *view() { return view_; }

    private:

    char *view_=nullptr;

    };

    共享内存管理类

    class  SharedMemory

    {

    public:

    SharedMemory() : hMapping_(NULL) {

    size_ = 0;

    m_hReadEvent = NULL;

    m_hWriteEvent = NULL;

    }

    ~SharedMemory() {

    Close();

        if (m_hReadEvent)

        {

    CloseHandle(m_hReadEvent);

        }

    if (m_hWriteEvent)

    CloseHandle(m_hWriteEvent);

    };

    public:

    //初始化

    bool InitReceiver(std::wstring name, std::wstring readName = L"ShareMemoryReadEvent", std::wstring writeName = L"ShareMemoryWriteEvent");//初始化接收方

    bool InitCreate(std::wstring name, int size,std::wstring readName=L"ShareMemoryReadEvent",std::wstring writeName=L"ShareMemoryWriteEvent");  //初始化创建方

    private:

    bool CreateFileMap();

    bool OpenFileMap();

    bool MapView(bool bCanWrite = true);

    void Close();

        public:

    char* getData();

    int getSize()

    {

    return size_;

    }

    public:

    //信号量管理

    void WaitForSingleObject_Read();

    void WaitForSingleObject_Write();

    void ResetEventNull_Read();

    void ResetEventNull_Write();

    void SetEvent_Read();

    void SetEvent_Write();

    private:

    friend class MappedView;

    MappedView View_;

    HANDLE hMapping_=nullptr;

    int size_=0;

    std::wstring name_;

    public:

    HANDLE m_hReadEvent=nullptr;

    HANDLE m_hWriteEvent=nullptr;

    std::wstring m_ReadEventName;  // 跨进程信号量 以 L"Global\\" 开头

    std::wstring m_WriteEventName;

    };

    应用实例:

      主进程发送摄像头数据

    主进程

    SharedMemory m_memMng;

    m_memMng.InitCreate(L"sharedCamera", 1920 * 1080 * 3 / 2 + 12);//0|1状态 +宽+高

    ////////////////////////////////////////////////////////////////

    char* pData = m_memMng.getData();

    INT32 nFps = g_pLiveForm->m_videoFps;

    INT32 nWidth = width;

    INT32 nHeight = height;

    INT32 Info[] = { nFps, nWidth, nHeight };

    int len = sizeof(Info) / sizeof(Info[0]);

    if (pData)

    {

    m_memMng.WaitForSingleObject_Read();

    m_memMng.ResetEventNull_Write();

    memcpy((INT32*)pData, Info, sizeof(INT32)*len);

    memcpy(pData + 12, nim_nls::LssManange::GetVideoFrameMng()->capture_video_pic_.pdata_, nim_nls::LssManange::GetVideoFrameMng()->capture_video_pic_.size_);

    m_memMng.SetEvent_Write();

    }

     子进程读摄像头数据

    SharedMemory m_memMng;

    m_memMng.InitReceiver(L"sharedCamera");

    //读取

    m_memMng.WaitForSingleObject_Write(); // WaitForSingleObject(m_memMng.m_hWriteEvent, INFINITE);

    m_memMng.ResetEventNull_Read();      //    ResetEvent(m_memMng.m_hReadEvent);

    char* pData = m_memMng.getData();

    if (pData)

    {

    INT32 nFps = 20;

    INT32 nWidth = width_;

    INT32 nHeight = height_;

    INT32 Info[] = { 0, nWidth, nHeight };

    int len = sizeof(Info) / sizeof(Info[0]);

    memcpy(Info, (INT32*)pData, sizeof(INT32)*len);

    nFps = Info[0];

    nWidth = Info[1];

    nHeight = Info[2];

            memcpy((char*)data_temp.c_str(), pData + 12, nWidth*nHeight * 3 / 2);

    m_memMng.SetEvent_Read();        //SetEvent(m_memMng.m_hReadEvent);

        }

    相关文章

      网友评论

          本文标题:共享内存

          本文链接:https://www.haomeiwen.com/subject/jcfrkctx.html