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

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

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

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

Ответы

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

Используйте новое размещение для создания вектора в общей памяти. Вам также понадобится распределитель для вектора, чтобы он мог использовать разделяемую память для хранения элементов. Если вектор просто хранит int, и вы можете поместить раздел разделяемой памяти на один и тот же виртуальный адрес в каждом процессе, это может сработать.

Ответ 4

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

Ответ 5

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

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

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