c++ - куче - выделение памяти под вектор




Можно ли разместить std:: vector в общую память? (4)

Вы можете использовать разделяемую память, отображаемую по фиксированному адресу , т. Е. Адрес будет одинаковым в каждом процессе, позволяя использовать необработанные указатели.

Поэтому, если вы сделаете что-то вроде следующего, вы можете иметь (несколько) областей разделяемой памяти:

#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 ).

я хотел бы создать std :: vector в общей памяти с помощью функции API Windows CreateFileMapping (). Я знаю, как создать общую память и управлять ею, но как разместить std :: vector на фиксированный адрес в памяти? Я не могу использовать boost или другие библиотеки в моем случае, я использую CBuilder ++ 2010. Один из вариантов, я думаю, может быть использован

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

Но как определить реальный размер векторов для изменения размера памяти?


Для этого вам нужно реализовать свой собственный распределитель. Распределитель является параметром std::vector<> .


Я бы использовал 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 имеет свой собственный векторный класс, который предназначен для того, что вы пытаетесь сделать.


Фактически, вы должны сделать то же : использовать новое место для создания экземпляра std::vector в общей памяти. И использовать специальный распределитель, чтобы сделать вектор размещением своих данных в общей памяти.

Имейте в виду, что вам нужно синхронизировать любой доступ к вектору (за исключением случаев, когда вам нужен только доступ на чтение). std::vector не является поточнобезопасным и не объявляет какой-либо из его членов volatile , что делает одновременный доступ из область действия компилятора - как это происходит в области разделяемой памяти - чрезвычайно опасна.

... в конце концов, я бы этого не сделал . Общая память представляет собой очень низкоуровневую и очень сложную концепцию, она не подходит для высокоуровневых контейнеров данных, таких как std::vector , на языке, который (с cpp03) не предоставляет хороших встроенных решений для параллелизма проблемы, и это не осознает, что существует нечто вроде разделяемой памяти.

... он может даже вызвать неопределенное поведение : в то время как std::vector обычно использует свой allocator для извлечения памяти для своих элементов, он (насколько мне известно) позволил выделить дополнительную память (то есть для внутренних целей, что бы это ни было ) с использованием malloc или любой другой стратегии распределения (я думаю, что реализация std::vector Microsoft делает это в отладочных сборках) ... эти указатели будут действительны только для одной стороны отображения памяти.

Чтобы избежать std::vector , я бы просто выделил достаточную память в заранее отображенном диапазоне и использовал простой счетчик, чтобы сохранить количество действительных элементов. Это должно быть безопасно.





stl