Возможно ли разместить 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
).