共享内存

2019-07-11  本文已影响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);

    }

上一篇下一篇

猜你喜欢

热点阅读