是否可以将std :: vector放到共享内存中?

时间:2011-03-19 17:26:57

标签: c++ stl

我想使用CreateFileMapping()windows API函数在共享内存中创建std :: vector。我知道如何创建共享内存并管理它,但是如何将std :: vector放到内存中的固定地址? 我不能在我的情况下使用boost或其他库,我正在使用CBuilder ++ 2010。 我认为一个变种可能是使用

std::vector<int> myVec; 
myVec *mv;
mv = shared_memory_addr ?

但我如何检测矢量的实际大小以调整内存大小?

5 个答案:

答案 0 :(得分:7)

我使用Boost.Interprocess,它解释了如何做到这一点: http://www.boost.org/doc/libs/1_38_0/doc/html/interprocess/quick_guide.html#interprocess.quick_guide.qg_interprocess_container

请注意,这不使用std::vector<>,它不适合共享内存使用,因为它通常用三个指针(开头,结尾,容量或某些等价物)实现,并且地址将流程不同。所以Boost.Interprocess有自己的vector类,它是专为你想要做的而构建的。

答案 1 :(得分:5)

实际上,您必须同时执行:使用placement new在共享内存中构造std::vector实例并使用自定义分配器使向量将其数据放在共享内存中好。

请记住,您需要同步对向量的任何访问(除非您只需要读访问权限) - std::vector通常不是线程安全的,并且不会声明其任何成员{{1} },这使得同时访问编译器的范围 - 因为它发生在共享内存区域 - 非常危险。

......毕竟,我不会这样做。共享内存是一个非常低级,非常棘手的概念,它不适合高级数据容器,例如volatile,其语言(从cpp03开始)不提供良好的内置解决方案并发问题,并不知道共享内存之类的东西存在。

...它甚至可能触发未定义的行为:虽然std::vector通常使用其std::vector来获取其元素的存储空间,但是(据我所知)允许使用allocator或任何其他分配策略(我认为Microsoft的malloc实现在调试版本中执行此操作)分配更多内存(即用于内部目的,无论可能是什么)...这些指针只会对内存映射的一方有效。

为了避免std::vector,我只是在前面的映射范围内分配足够的内存,并使用一个简单的计数器来保持有效元素的数量。这应该是安全的。

答案 2 :(得分:1)

使用placement new在共享内存中构造向量。您还需要一个矢量分配器,以便它可以使用共享内存进行元素存储。如果向量只是存储int,并且您可以将共享内存部分放在每个进程的同一个虚拟地址中,这可能会起作用。

答案 3 :(得分:1)

您需要实现自己的分配器才能实现这一目标。分配器是std::vector<>模板参数。

答案 4 :(得分:1)

您可以使用映射在固定地址的共享内存,即每个进程允许使用原始指针的地址相同。

因此,如果您执行以下操作,则可以拥有(多个)共享内存区域:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>

struct MySegment {
    static const size_t alloc_size = 1048576;
    static const void *getAddr() { return (void *)0x400000000LL; }
    static const char *getSegmentName() { return "MySegment"; }
};

template <typename MemorySegment>
class SharedMemory {
public:
    typedef boost::interprocess::fixed_managed_shared_memory shared_memory_t;
    typedef shared_memory_t::segment_manager segment_manager_t;

    static shared_memory_t *getSegment() {
        if (!segment) {
            assert(MemorySegment::getAddr() != 0 && "want a fixed address for all processes");
            segment = new boost::interprocess::managed_shared_memory(
                    boost::interprocess::open_or_create,
                    MemorySegment::getSegmentName(),
                    MemorySegment::alloc_size,
                    MemorySegment::getAddr());
        }
        return segment;
    }
    static segment_manager_t *getSegmentManager() {
        return getSegment()->get_segment_manager(); }

private:
    static boost::interprocess::managed_shared_memory *segment;
};
template <typename MemorySegment>
typename SharedMemory<MemorySegment>::shared_memory_t *SharedMemory<MemorySegment>::segment = NULL;


template <class MemorySegment, class T>
class SharedMemoryAllocator {
public:
    typedef boost::interprocess::allocator<T, typename SharedMemory<MemorySegment>::segment_manager_t> InterprocessAllocator;

    // Delegate all calls to an instance of InterprocessAllocator,
    pointer allocate(size_type n, const void *hint = 0) { return TempAllocator().allocate(n, hint); }
    void deallocate(const pointer &p, size_type n) { return TempAllocator().deallocate(p, n); }
    size_type max_size() const { return TempAllocator().max_size(); }
    void construct(const pointer &ptr, const_reference v) { return TempAllocator().construct(ptr, v); }
    void destroy(const pointer &ptr) { return TempAllocator().destroy(ptr); }

    typedef typename InterprocessAllocator::value_type value_type;
    typedef typename InterprocessAllocator::pointer pointer;
    typedef typename InterprocessAllocator::reference reference;
    typedef typename InterprocessAllocator::const_pointer const_pointer;
    typedef typename InterprocessAllocator::const_reference const_reference;
    typedef typename InterprocessAllocator::size_type size_type;
    typedef typename InterprocessAllocator::difference_type difference_type;

    SharedMemoryAllocator() {}
    template <class U> SharedMemoryAllocator(const SharedMemoryAllocator<MemorySegment, U> &u) {}

    template <typename OtherT> struct rebind { typedef SharedMemoryAllocator<MemorySegment, OtherT> other; };

private:
    static InterprocessAllocator TempAllocator() {
        return InterprocessAllocator(SharedMemory<MemorySegment>::getSegmentManager());
    }
};

然后,您可以使用:

       std::vector<int, SharedMemoryAllocator<MySegment, int> vec;

并且向量的元素将放在共享内存中(当然,vec也必须在那里分配)。