SharedMemory容器问题

时间:2015-06-02 19:39:19

标签: c++ containers shared-memory

我已经为测试共享内存分配器和容器创建了以下代码..

分配器(只保留指向内存块的指针的基本分配器+大小:

template<typename T>
struct SharedMemoryAllocator
{
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;

    void* memory;
    std::size_t size;


    SharedMemoryAllocator(void* memory, std::size_t size) noexcept : memory(memory), size(size) {};
    SharedMemoryAllocator(const SharedMemoryAllocator& other) noexcept : memory(other.memory), size(other.size) {};

    template<typename U>
    SharedMemoryAllocator(const SharedMemoryAllocator<U>& other) noexcept : memory(other.memory), size(other.size) {};

    template<typename U>
    SharedMemoryAllocator& operator = (const SharedMemoryAllocator<U>& other) { return *this; }
    SharedMemoryAllocator<T>& operator = (const SharedMemoryAllocator& other) { return *this; }
    ~SharedMemoryAllocator() {}

    pointer address(reference value) const {return &value;}
    const_pointer address(const_reference value) const {return &value;}

    pointer allocate(size_type n, const void* hint = 0) {return static_cast<T*>(memory);}
    void deallocate(T* ptr, size_type n) {}

    template<typename U, typename... Args>
    void construct(U* ptr, Args&&... args) {::new(static_cast<void*>(ptr)) U(std::forward<Args>(args)...);}
    void construct(pointer ptr, const T& val) {new(static_cast<T*>(ptr)) T(val);}

    template<typename U>
    void destroy(U* ptr) {ptr->~U();}
    void destroy(pointer ptr) {ptr->~T();}

    size_type max_size() const {return size / sizeof(T);}

    template<typename U>
    struct rebind {typedef SharedMemoryAllocator<U> other;};
};

template <typename T, typename U>
inline bool operator == (const SharedMemoryAllocator<T>& a, const SharedMemoryAllocator<U>& b)
{
    return (a == b);
}

template <typename T, typename U>
inline bool operator != (const SharedMemoryAllocator<T>& a, const SharedMemoryAllocator<U>& b)
{
    return !(a == b);
}

容器(只是使用SharedMemory分配器分配内存的容器):

template<typename T, typename allocator = std::allocator<T>>
class CVector
{
private:
    T* memory;
    std::size_t size, capacity;
    allocator alloc;

public:
    CVector() : memory(nullptr), size(0), capacity(0), alloc(allocator()) {}
    CVector(const allocator &alloc) : memory(nullptr), size(0), capacity(0), alloc(alloc) {}
    ~CVector()
    {
        if(memory)
        {
            for(std::size_t i = 0; i < this->size; ++i)
            {
                alloc.destroy(memory + i);
            }

            alloc.deallocate(memory, capacity);
            memory = nullptr;
        }
    }

    void reserve(std::size_t size)
    {
        if(capacity < size)
        {
            capacity = size;
            void* mem = alloc.allocate(capacity);

            if(memory && memory != mem)
            {
                memcpy(static_cast<char*>(mem), memory, size * sizeof(T));

                for(std::size_t i = 0; i < this->size; ++i)
                {
                    alloc.destroy(memory + i);
                }

                alloc.deallocate(memory, capacity);
                memory = nullptr;
            }

            memory = static_cast<T*>(mem);
        }
    }

    void push_back(T&& value)
    {
        if(capacity == 0)
        {
            reserve(1);
        }

        if(size >= capacity)
        {
            reserve(capacity * 2);
        }

        alloc.construct(memory + size++, value);
    }

    T& operator[](std::size_t size)
    {
        return *(memory + size);
    }

    const T& operator[](std::size_t size) const
    {
        return *(memory + size);
    }
};

主:

int main()
{
    MemoryMap mem{"Local\\Test", 5000, std::ios::in | std::ios::out};
    mem.open();
    mem.map();

    typedef CVector<int, SharedMemoryAllocator<int>> SHMVec;


    SHMVec* vec = ::new(mem.data()) SHMVec(SharedMemoryAllocator<int>(static_cast<char*>(mem.data()) + sizeof(SHMVec), 1024 - sizeof(SHMVec)));

    vec->reserve(100);
    vec->push_back(100);
    vec->push_back(200);
    vec->push_back(300);

    std::cout<<"Address: "<<mem.data()<<"\n";
    std::cin.get();

    SHMVec* ptrVec = reinterpret_cast<SHMVec*>(mem.data());
    std::cout<<(*ptrVec)[0];


    vec->~SHMVec();
}

我在某处读到std :: vector不能放在SharedMemory中,因为它可能会在当前进程的地址空间中对它自己进行一些跟踪。所以我决定写自己的&#34; vector&#34;这只是一个廉价的课程。

接下来,我分配一个共享内存块,然后将容器构建到该块中,如上所示&#34; main&#34;。

在另一个程序中,我做(主要):

int main()
{
    MemoryMap mem{"Local\\Test", 5000, std::ios::in};
    mem.open();
    mem.map();

    typedef CVector<int, SharedMemoryAllocator<int>> SHMVec;

    std::cout<<"Address: "<<mem.data()<<"\n";
    SHMVec* ptrVec = reinterpret_cast<SHMVec*>(mem.data());
    std::cout<<(*ptrVec)[0];
}

当两个程序将共享内存块映射到0x370000时,它可以工作。但是,如果一个程序在0x370000处分配SharedMemoryBlock而在0x380000处分配第二个程序,则它会崩溃(第二个程序崩溃尝试访问第一个创建的容器)。

为什么会这样?容器位于共享内存块中。为什么块的地址必须完全相同才重要?

2 个答案:

答案 0 :(得分:2)

这是你的问题:

template<typename T, typename allocator = std::allocator<T>>
class CVector
{
private:
    T* memory;
    ^^^^^^^^^^^

因为在程序中SHMVector对象本身存储在共享内存中,所以将其数据成员存储在共享内存中。因此,指向元素的指针(在这种情况下为memory)存储在共享存储器中。

如果共享内存段加载到不同的地址,则memory将指向两个程序之一的内存空间中的无效地址。

也许是简单的解决方案:不要将SHMVec对象本身放在共享内存中,只放在元素中。

答案 1 :(得分:0)