我想使用CreateFileMapping()windows API函数在共享内存中创建std :: vector。我知道如何创建共享内存并管理它,但是如何将std :: vector放到内存中的固定地址? 我不能在我的情况下使用boost或其他库,我正在使用CBuilder ++ 2010。 我认为一个变种可能是使用
std::vector<int> myVec;
myVec *mv;
mv = shared_memory_addr ?
但我如何检测矢量的实际大小以调整内存大小?
答案 0 :(得分:7)
我使用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有自己的vector类,它是专为你想要做的而构建的。
答案 1 :(得分:5)
实际上,您必须同时执行:使用placement new在共享内存中构造std::vector
实例并使用自定义分配器使向量将其数据放在共享内存中好。
请记住,您需要同步对向量的任何访问(除非您只需要读访问权限) - std::vector
通常不是线程安全的,并且不会声明其任何成员{{1} },这使得同时访问编译器的范围 - 因为它发生在共享内存区域 - 非常危险。
......毕竟,我不会这样做。共享内存是一个非常低级,非常棘手的概念,它不适合高级数据容器,例如volatile
,其语言(从cpp03开始)不提供良好的内置解决方案并发问题,并不知道共享内存之类的东西存在。
...它甚至可能触发未定义的行为:虽然std::vector
通常使用其std::vector
来获取其元素的存储空间,但是(据我所知)允许使用allocator
或任何其他分配策略(我认为Microsoft的malloc
实现在调试版本中执行此操作)分配更多内存(即用于内部目的,无论可能是什么)...这些指针只会对内存映射的一方有效。
为了避免std::vector
,我只是在前面的映射范围内分配足够的内存,并使用一个简单的计数器来保持有效元素的数量。这应该是安全的。
答案 2 :(得分:1)
使用placement new在共享内存中构造向量。您还需要一个矢量分配器,以便它可以使用共享内存进行元素存储。如果向量只是存储int,并且您可以将共享内存部分放在每个进程的同一个虚拟地址中,这可能会起作用。
答案 3 :(得分:1)
您需要实现自己的分配器才能实现这一目标。分配器是std::vector<>
模板参数。
答案 4 :(得分:1)
您可以使用映射在固定地址的共享内存,即每个进程允许使用原始指针的地址相同。
因此,如果您执行以下操作,则可以拥有(多个)共享内存区域:
#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
也必须在那里分配)。