共享内存中带有 boost::interprocess 分配器的 std::unordered_map - 缺点?
我现在正在使用 boost::interprocess
进入共享内存.
I'm right now getting into shared memory using boost::interprocess
.
我以如下方式定义了一些 std::unordered_map
和 std::unordered_set
类型:
I've defined a few std::unordered_map
and std::unordered_set
types like in the following manner:
#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);
这似乎工作正常,我在编译或运行期间没有发现任何问题(在 macOS 上工作,Apple LLVM version 9.1.0 (clang-902.0.39.1)
,使用 C++14 标准).
This seems to work fine, i haven't found any problems during compile- or runtime (working on macOS, Apple LLVM version 9.1.0 (clang-902.0.39.1)
, with C++14 standard).
在 Boost 文档中,只提到了 Boost 容器或特定于进程间的实现.不幸的是,它们似乎不包含无序版本.
In the Boost documentation, only the Boost containers, or the interprocess-specific implementations are mentioned. Unfortunately, they do not seem to contain the unordered versions.
那么,我想知道将默认 STL 容器与 Boost 分配器一起使用是否有任何问题?也许在不同的平台上?
So, i wonder if there's anything problematic about using the default STL containers with the Boost allocators ? Maybe on a different platform ?
任何提示表示赞赏!
更新:
我想知道它是否在不同的环境中工作,所以我写了一个关于 Coliru 的最小示例(它令人惊讶地与 std::string
一起使用):
I was wondering if it was working in a different environment, so i wrote a minimal example on Coliru (which surprisingly works with std::string
):
http://coliru.stacked-crooked.com/a/91d1a143778cf3e9
推荐答案
unordered_map
将处理 Boost Interprocess 分配器 如果您的库实现支持有状态分配器1和使用非原始指针类型的分配器.
unordered_map
will cope with Boost Interprocess allocators IFF your library implementation has support for stateful allocators1 and allocators using non-raw pointer types.
即便如此,就像@rustyx 提到的那样,如果您实际上与另一个进程共享内存,您将会遇到很大的麻烦.另一个进程可能会将段映射到不同的基地址,从而使存储在内存区域内的所有指针都无效.
Even so, like @rustyx mentions, you're going to be in deep trouble if you actually share the memory with another process. The other process is likely to map the segment at a different base address, making all pointers stored inside the memory region invalid.
?你需要也使用带有字符串的进程间分配器!
? You need to use a Interprocess allocator with the string too!
以下是我通常更喜欢写的内容:
Here's what I usually prefer to write:
#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()));
}
值得注意的细节:
这一点:
This bit:
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);
这是可行的,因为允许从段管理器指针到分配器实例的隐式转换.
This works because the implicit conversion from segment-manager pointer to allocator instance is allowed.
进入魔法
您会注意到嵌套分配器使用起来很笨拙:
Enter MAGIC
You'll note that the nested allocator is clumsy to work with:
m.emplace(42, Shared::String("LtUaE", msm.get_segment_manager()));
这就是 scoped_allocator_adaptor
的设计者试图解决的问题.如果将分配器更改为:
That's what the designers of scoped_allocator_adaptor
tried to solve. If you change the allocator into:
template <typename T> using Alloc = std::scoped_allocator_adaptor<ipc::allocator<T, Manager> >;
你可以突然写:
m.emplace(42, "LtUaE");
这是因为就地构造是根据用途定义的-分配器构造(参见[allocator.uses.construction])
This is because in-place construction is defined in terms of uses- allocator construction (see [allocator.uses.construction])
看到它住在 Coliru
1 准备好惊讶吧,@SergeyA.我上次检查时 Libstdc++ 不支持这个,但它的 unordered_map
自 GCC 4.9.0 开始支持它,而且 OP 似乎有传闻证据表明 libc++ 支持(尽管我们甚至不知道是否有曾经是 typedef 的一个实例 :))
1 prepare to be surprised, @SergeyA. Libstdc++ didn't support this last time I checked, but its unordered_map
supports it since GCC 4.9.0, and OP seems to have anecdotal evidence that libc++ does (although we don't even know whether there was ever an instance of the typedef :))
相关文章