我已经为测试共享内存分配器和容器创建了以下代码..
分配器(只保留指向内存块的指针的基本分配器+大小:
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处分配第二个程序,则它会崩溃(第二个程序崩溃尝试访问第一个创建的容器)。
为什么会这样?容器位于共享内存块中。为什么块的地址必须完全相同才重要?
答案 0 :(得分:2)
这是你的问题:
template<typename T, typename allocator = std::allocator<T>>
class CVector
{
private:
T* memory;
^^^^^^^^^^^
因为在程序中SHMVector对象本身存储在共享内存中,所以将其数据成员存储在共享内存中。因此,指向元素的指针(在这种情况下为memory
)存储在共享存储器中。
如果共享内存段加载到不同的地址,则memory
将指向两个程序之一的内存空间中的无效地址。
也许是简单的解决方案:不要将SHMVec对象本身放在共享内存中,只放在元素中。
答案 1 :(得分:0)
boost :: interprocess可以帮助您将容器保存在共享内存中 - 请参阅http://www.boost.org/doc/libs/1_38_0/doc/html/interprocess/allocators_containers.html#interprocess.allocators_containers.containers_explained.containers