2

我正在尝试将 std::map 存储在共享内存段上。但我无法恢复地图。

我创建共享内存段(使用下面的类)并将映射地址分配给它。

但是当我试图恢复它时,我得到了一个错误的指针。

以下是一些代码片段:

    // This is in my header file
    CSharedMem * shMem;
    // This is in my cpp file - inside my class constructor
    shMem = new CSharedMem("MyShMem", 16536);
    void * ptr = shMem->GetAddress();
    std::map<int,int> myMap;
    ptr = &myMap;
    shMem-ReleaseAddress();

    // This is inside another function
    void * ptr = shMem->GetAdress();

    std::map<int,int> myMap = *static_cast<std::map<int,int> *> (ptr);

有人有线索吗?

CSharedMem 类头文件:

    #pragma once

    #include <string>

    class CSharedMem
    {
    public:
    CSharedMem(const std::string& name, std::size_t size);
    ~CSharedMem();

    void* GetAddress() const;
    void ReleaseAddress();
    bool IsShared() const;
    private:
    bool shared_;
    void* address_;

    private:
    void* shm_;
    void* mtx_;
    };

cpp文件:

    #include "StdAfx.h"
    #include "SharedMem.h"
    #include <windows.h>
    CSharedMem::CSharedMem(const std::string& name, std::size_t size)
    : shared_(false), 
    address_(NULL)
    {
    shm_ = CreateFileMapping(INVALID_HANDLE_VALUE, 
                            NULL, PAGE_READWRITE, 
                            0, 
                            static_cast<DWORD>(size), 
                            name.c_str() );
    if( shm_ == INVALID_HANDLE_VALUE )
            throw std::exception("Failed to allocate shared memory.");

    if( GetLastError() == ERROR_ALREADY_EXISTS )
            shared_ = true;

    address_ = MapViewOfFile(shm_, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
    if( address_ == NULL )
            throw std::exception("Failed to map shared memory.");

    if( !shared_ )
            std::memset(address_, 0, size);

    mtx_ = CreateMutex(NULL, FALSE, (name + "MTX").c_str());
    if( mtx_ == INVALID_HANDLE_VALUE )
            throw std::exception("Failed to create shared mutex.");
    }

    CSharedMem::~CSharedMem()
    {
    UnmapViewOfFile(address_);
    CloseHandle(mtx_);
    }
    void* CSharedMem::GetAddress() const
    {
    if(WaitForSingleObject(mtx_, INFINITE) != WAIT_OBJECT_0)
            throw std::exception("Failed to obtain access to shared memory.");

    return address_;
    }

    void CSharedMem::ReleaseAddress()
    {
            ReleaseMutex(mtx_);
    }

    bool CSharedMem::IsShared() const
    {
            return shared_;
    }
4

2 回答 2

4

这种逻辑有些可疑:

void * ptr = shMem->GetAddress();
std::map<int,int> myMap;
ptr = &myMap;
shMem->ReleaseAddress();

请注意,您使用 获得了地址shMem->GetAddress(),但随后声明了一个局部变量myMap,然后分配ptr了该局部变量的地址。这意味着您实际上将不再ptr指向该共享内存。

我不确定对此的解决方法是什么,因为我不确定我是否看到您在这里尝试做的事情。如果您打算将共享内存转换为指向映射的指针,也许您的意思是:

void * ptr = shMem->GetAddress();

/* Construct a map at the given address using placement new. */
new (ptr) std::map<int, int>();
shMem-ReleaseAddress();

稍后,您可以检索地图:

void* ptr = shMem->GetAdress();

/* Note the use of a reference here so we don't just make a copy. */
std::map<int,int> myMap& = *static_cast<std::map<int,int> *> (ptr);

也就是说,我非常怀疑这是否会起作用,因为在内部分配的指针map对于创建它们的进程来说是本地的,而不是共享的。您可能需要对分配器做一些花哨的事情才能使其正常工作。

希望这可以帮助!

于 2012-06-20T02:22:33.960 回答
4

根据上面的评论,这并不像听起来那么简单。如果跨进程使用共享内存,则不能传递 STL 容器。

However, you can use the containers in the boost::interprocess library. This library specifically provides containers (vector, deque, set, map) that can be used within a shared memory segment, and the documentation provides lots of examples.

于 2012-06-20T03:05:52.710 回答