c++ 是否可以将std::vector放入共享内存?

56lgkhnf  于 2023-02-14  发布在  其他
关注(0)|答案(5)|浏览(496)

我想使用CreateFileMapping() windows API函数在共享内存中创建一个std::vector。我知道如何创建和管理共享内存,但如何将std::vector分配到内存中的固定地址?我无法使用boost或其他库,我使用的是CBuilder++ 2010。我认为可能使用的一个变体是

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

但是,如何检测向量的真实的大小来调整内存大小呢?

zf2sa74q

zf2sa74q1#

我会使用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<>std::vector<>不适合共享内存使用,因为它通常是用三个指针(开始、end、capacity或一些等价的指针)来实现的,并且地址在进程之间会有所不同,所以Boost.Interprocess有自己的vector类,这是专门为您要做的事情而构建的。

0pizxfdo

0pizxfdo2#

  • 实际上,你必须两者兼顾 *:使用placement new在共享内存中构造std::vector示例,并使用自定义分配器使向量也将其数据放置在共享内存中。

请记住,您需要同步对向量的任何访问(除非您只需要读访问)-std::vector通常不是线程安全的,并且不声明其任何成员volatile,这使得在编译器作用域之外的同时访问(就像在共享内存区域中发生的那样)非常危险。
...毕竟,我不会这么做共享内存是一个非常低级、非常棘手的概念,它并不适合std::vector这样的高级数据容器,在一种语言中(截至cpp 03),它没有为并发问题提供良好的内置解决方案,也没有意识到类似共享内存的东西的存在。
......它甚至可能触发未定义的行为:虽然std::vector通常使用其allocator来为其元素获取存储空间,但(据我所知)允许分配更多的内存(即用于内部目的,无论是什么)使用X1 M6 N1 X或任何其它分配策略(我认为微软的std::vector实现在调试版本中做到了这一点)...这些指针只对内存Map的一侧有效。
为了避免std::vector,我只需要在Map范围中预先分配足够的内存,并使用一个简单的计数器来保存有效元素的数量,这应该是安全的。

cyej8jka

cyej8jka3#

您需要实现自己的分配器来实现这一点。分配器是一个std::vector<>模板参数。

ttisahbt

ttisahbt4#

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

zpjtge22

zpjtge225#

你可以使用共享内存,Map到一个 * 固定地址 *,也就是说,地址在每个进程中都是相同的,允许使用原始指针。
因此,如果您执行以下操作,就可以拥有(多个)共享内存区域:

#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也必须被分配到那里)。

相关问题