我现在正在使用boost::interprocess
进入共享内存。
我已按照以下方式定义了一些std::unordered_map
和std::unordered_set
类型:
#include <boost/interprocess/allocators/allocator.hpp>
#include <unordered_map> // NOT the boost implementation ...
...
namespace ipc = boost::interprocess;
/**
* allocator type needed to construct maps in shared memory
*/
typedef ipc::allocator<std::pair<const size_t, std::string>,
ipc::managed_shared_memory::segment_manager> OBJ_MAP_ALLOCATOR;
/**
* map type to construct maps in shared memory
*/
typedef std::unordered_map<size_t,
std::string,
std::hash<size_t>,
std::equal_to<size_t>,
OBJ_MAP_ALLOCATOR> OBJ_MAP_TYPE;
我将它们初始化为:
ipc::managed_shared_memory segment;
// allocate segment etc ...
OBJ_MAP_ALLOCATOR alloc_inst(segment.get_segment_manager());
objMap = segment.find_or_construct<OBJ_MAP_TYPE> (ipc::unique_instance)(alloc_inst);
这似乎工作正常,我在编译或运行时没有发现任何问题(使用C ++ 14标准处理macOS,Apple LLVM version 9.1.0 (clang-902.0.39.1)
)。
在Boost文档中,仅提到了Boost容器或特定于进程间的实现。不幸的是,它们似乎没有包含无序版本。
所以,我想知道在使用Boost分配器的默认STL容器时是否存在任何问题?也许在不同的平台上?
任何暗示都表示赞赏!
更新
我想知道它是否在不同的环境中工作,所以我写了一个关于Coliru的最小例子(令人惊讶地与std::string
一起工作):
答案 0 :(得分:5)
unordered_map
将处理Boost进程间分配器IFF你的库实现支持使用非原始指针类型的有状态分配器¹和分配器。
即便如此,就像@rustyx提到的那样,如果实际与另一个进程共享内存,那么你将陷入深深的麻烦。另一个进程可能会将段映射到不同的基址,使存储在内存区域内的所有指针都无效。
☞您需要使用带有字符串的进程间分配器!
以下是我通常喜欢写的内容:
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <unordered_map>
namespace ipc = boost::interprocess;
namespace Shared {
using Segment = ipc::managed_shared_memory;
using Manager = Segment::segment_manager;
template <typename T> using Alloc = ipc::allocator<T, Manager>;
template <typename K, typename V, typename KH = std::hash<K>, typename KEq = std::equal_to<K> >
using HashMap = std::unordered_map<K, V, KH, KEq, Alloc<std::pair<const K, V>> >;
using String = ipc::basic_string<char, std::char_traits<char>, Alloc<char> >;
}
using OBJ_MAP_TYPE = Shared::HashMap<size_t, Shared::String>;
int main() {
Shared::Segment msm(ipc::open_or_create, "test", 10ul<<20);
Shared::Manager* mgr = msm.get_segment_manager();
OBJ_MAP_TYPE& m = *msm.find_or_construct<OBJ_MAP_TYPE>("aname")(msm.get_segment_manager());
m.emplace(42, Shared::String("LtUaE", msm.get_segment_manager()));
}
值得注意的细节:
这一位:
Shared::Manager* mgr = msm.get_segment_manager();
OBJ_MAP_TYPE& m = *msm.find_or_construct<OBJ_MAP_TYPE>("aname")(mgr);
是一个方便的捷径:
Shared::Alloc<OBJ_MAP_TYPE::value_type> alloc_inst(msm.get_segment_manager());
OBJ_MAP_TYPE& m = *msm.find_or_construct<OBJ_MAP_TYPE>("aname")(alloc_inst);
这是有效的,因为允许从段管理器指针到分配器实例的隐式转换。
您会注意到嵌套分配器使用起来很笨:
m.emplace(42, Shared::String("LtUaE", msm.get_segment_manager()));
这就是scoped_allocator_adaptor
的设计师试图解决的问题。如果您将分配器更改为:
template <typename T> using Alloc = std::scoped_allocator_adaptor<ipc::allocator<T, Manager> >;
你可以突然写下:
m.emplace(42, "LtUaE");
这是因为就地建筑是根据用途而定义的─ 分配器构造(参见 [allocator.uses.construction] )
¹准备惊讶,@ SergeyA。 Libstdc ++上次我检查时不支持这个,但是它的unordered_map
支持它自GCC 4.9.0以来,OP似乎有证据证明libc ++有(尽管我们甚至不知道是否有实例) of typedef:))