问题描述
在boost::interprocess::managed_shared_memory
内,我试图在另一个boost::unordered_map
内创建boost::unordered_map
作为值,两个映射的键都为std::string
.共享内存段中Map中的Map通过两个不同的进程进行访问,这两个进程均从外部&内部地图.
Inside a boost::interprocess::managed_shared_memory
, I am trying to create boost::unordered_map
inside another boost::unordered_map
as value, having key as std::string
for both maps. This Map in Map inside a shared memory segment gets accessed by two different processes fetch values from both outer & inner maps.
下面是我的实现&想知道这是否可能/正确的方法或其他更好的方法?
Below is my implementation & want to know if this is possible/right way or any other better way possible?
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_or_create, "BOOST_SHM", 65536);
typedef std::string KeyType;
typedef std::string ValueType;
typedef std::pair<const KeyType, ValueType> MapType;
typedef boost::interprocess::allocator<MapType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::unordered_map<KeyType, ValueType, boost::hash<KeyType>, std::equal_to<KeyType>, ShmemAllocator> InMap;
ShmemAllocator alloc_inst(segment.get_segment_manager());
InMap *inside_map = segment.construct<InMap>("SHM_IN_MAP")(3, boost::hash<KeyType>(), std::equal_to<KeyType>(), alloc_inst);
typedef std::pair<const KeyType, MapType> MIMType;
typedef boost::interprocess::allocator<MIMType, boost::interprocess::managed_shared_memory::segment_manager> MIMShmemAllocator;
typedef boost::unordered_map<KeyType, MapType, boost::hash<KeyType>, std::equal_to<KeyType>, MIMShmemAllocator> OutMap;
//MIMShmemAllocator alloc_inst(segment.get_segment_manager()); /*Commented due to Error*/
OutMap *outside_map = segment.construct<OutMap>("SHM_OUT_MAP")(3, boost::hash<KeyType>(), std::equal_to<KeyType>(), alloc_inst);
其他详细信息:
CentOS 7上的gcc版本4.8.3 20140911(Red Hat 4.8.3-9)(GCC)BOOST_LIB_VERSION"1_58"
gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) on CentOS 7,BOOST_LIB_VERSION "1_58"
推荐答案
确定.
因此,存在一些基本错误,并且可能有些混乱.
So there were a few basic errors, and possibly some confusion.
接下来,有一些强大的技巧使嵌套容器与自定义(有状态)分配器配合使用更加方便.
Next, there are some power tricks that make using nested containers with custom (stateful) allocators much more convenient.
这是工作示例中所有三个提示的汇总,希望能对您有所帮助!
Here's the roll-up of all three hints in a working sample that hopefully helps!
-
您的字符串也必须也使用共享内存分配器
Your strings must use shared memory allocators too
否则,在其他过程中使用该数据将是非法的.使用字符串将导致未定义的行为.
Otherwise the data would be illegal to use in another process. Using the strings would result in Undefined Behaviour.
至少,使您的字符串使用共享内存分配器:
At the very least, make your strings use the shared memory allocator:
namespace Shared {
using Segment = bip::managed_shared_memory;
template <typename T>
using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::container::basic_string<char, std::char_traits<char>, Alloc<char> >;
using KeyType = String;
using ValueType = String;
}
地图分配器被过度指定.无论如何,在映射中包裹pair<K const, v>
元素的实际节点类型都是实现定义的.那么地图如何知道如何分配这些节点?
The map allocators were overspecified. The actual node-types wrapping the pair<K const, v>
elements in a map are implementation defined anyways. So how do maps know how to allocate these nodes?
它们 重新绑定 分配器:请参见 rebind
在此处的文档中
They rebind allocators: see rebind
in the docs here
因此,您只需传递Alloc<void>
.或与Shared::String
相同的分配器.地图将找出答案:
So, you can just pass Alloc<void>
. Or the same allocator as for the Shared::String
. The map will figure it out:
typedef boost::unordered_map<KeyType, ValueType, boost::hash<KeyType>, std::equal_to<KeyType>, Alloc<void> > InMap;
typedef boost::unordered_map<KeyType, InMap, boost::hash<KeyType>, std::equal_to<KeyType>, Alloc<void> > OutMap;
现在是电源提示.
将状态分配器传递给所有令人困惑的时间很烦人.它使代码变得一团糟.幸运的是,c ++ 11(和c ++ 03的Boost容器)已经涵盖了:
Passing stateful allocators all the freaking time is annoying. It makes code a mess. Luckily, c++11 (and Boost Containers for c++03) has you covered:
-
scoped_allocator_adaptor<T...>
-
allocator_type
-
uses_allocator<T>
性状
scoped_allocator_adaptor<T...>
allocator_type
uses_allocator<T>
trait
这些助手可以使您的生活更加轻松.他们通过在适用时将分配器向下传递给元素类型构造函数来实现.自动地.再次,反弹分配器类型的隐式转换使事情正常进行.
These helpers can make your life a lot easier. They do this by passing the allocator down to element type constructors when applicable. Automatically. Again, implicit conversions from rebound allocator types make things work.
因此,您实际上可以仅使用正确的分配器(将其设为Scoped
)和一个键来构造一个外部映射,并且从那里甚至不必继续指定分配器./p>
So, you can actually just construct one outer map with the correct allocator (make it Scoped
) and one key, and from there you don't even have to keep specifying allocators.
这是完整的演示:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>
namespace bip = boost::interprocess;
namespace Shared {
using Segment = bip::managed_shared_memory;
template <typename T>
using Alloc = bip::allocator<T, Segment::segment_manager>;
using Scoped = boost::container::scoped_allocator_adaptor<Alloc<char> >;
using String = boost::container::basic_string<char, std::char_traits<char>, Scoped>;
using KeyType = String;
typedef boost::unordered_map<KeyType, String, boost::hash<KeyType>, std::equal_to<KeyType>, Scoped> InMap;
typedef boost::unordered_map<KeyType, InMap, boost::hash<KeyType>, std::equal_to<KeyType>, Scoped> OutMap;
}
int main() {
srand(time(NULL));
Shared::Segment segment(bip::open_or_create, "BOOST_SHM", 65536);
auto* mgr = segment.get_segment_manager();
Shared::OutMap *p_outside_map = segment.find_or_construct<Shared::OutMap> ("SHM_OUT_MAP") (mgr);
auto& outside_map = *p_outside_map;
Shared::String sskey(mgr); // reduce shared allocations as they are costly (in terms of fragmentation/overhead)
char outer_keys[3], inner_keys[3];
std::generate_n(outer_keys, 3, [] { return rand()%26+'a'; });
std::generate_n(inner_keys, 3, [] { return rand()%26+'a'; });
for (auto key : outer_keys) {
sskey = key;
auto& inner = outside_map[sskey];
for (auto more : inner_keys) {
inner[sskey + "_" + more] += "value";
}
}
for (auto const& oe : outside_map) {
for (auto const& ie : oe.second) {
std::cout << "outside_map[" << oe.first << "][" << ie.first << "] == " << ie.second << "\n";
}
}
}
实际上,要使其在Coliru上运行,我们需要改用映射文件:
Actually, to make it work on Coliru, we need to use a mapped file instead:
运行几次:
outside_map[s][s_t] == value
outside_map[s][s_r] == value
outside_map[s][s_c] == value
outside_map[f][f_t] == value
outside_map[f][f_r] == value
outside_map[f][f_c] == value
outside_map[o][o_t] == value
outside_map[o][o_r] == value
outside_map[o][o_c] == value
第二次运行:
outside_map[a][a_d] == value
outside_map[a][a_c] == value
outside_map[a][a_g] == value
outside_map[r][r_d] == value
outside_map[r][r_c] == value
outside_map[r][r_g] == value
outside_map[g][g_d] == value
outside_map[g][g_c] == value
outside_map[g][g_g] == value
outside_map[s][s_t] == value
outside_map[s][s_r] == value
outside_map[s][s_c] == value
outside_map[f][f_t] == value
outside_map[f][f_r] == value
outside_map[f][f_c] == value
outside_map[o][o_t] == value
outside_map[o][o_r] == value
outside_map[o][o_c] == value
请注意每次运行如何成功地将value
附加到3个内部映射中的9个键上.
Note how each run successfully appends value
to 9 keys in 3 inner maps.
这篇关于共享内存中分配的映射的映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!