Можно ли поместить std :: vector в общую память? - PullRequest
15 голосов
/ 19 марта 2011

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

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

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

Ответы [ 5 ]

7 голосов
/ 19 марта 2011

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

5 голосов
/ 19 марта 2011

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

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

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

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

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

1 голос
/ 09 мая 2011

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

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

#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 также должен быть выделен там).

1 голос
/ 19 марта 2011

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

1 голос
/ 19 марта 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...