std::unordered_map 在共享内存中使用 boost:::进程间分配器 - 缺点?
std::unordered_map with boost::interprocess allocator in shared memory - drawbacks?
我现在正在使用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);
这似乎工作正常,我在编译或运行时(在 macOS、Apple LLVM version 9.1.0 (clang-902.0.39.1)
上使用 C++14 标准)期间没有发现任何问题。
在 Boost 文档中,只提到了 Boost 容器或特定于进程间的实现。不幸的是,它们似乎不包含无序版本。
所以,我想知道将默认 STL 容器与 Boost 分配器一起使用是否有任何问题?也许在不同的平台上?
任何提示赞赏!
更新:
我想知道它是否在不同的环境中工作,所以我在 Coliru 上写了一个最小的例子(令人惊讶的是它适用于std::string
):
http://coliru.stacked-crooked.com/a/91d1a143778cf3e9
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");
这是因为就地施工是根据用途定义的- 分配器构造(参见[分配器.使用.构造])
在科里鲁现场观看
¹ 准备好迎接惊喜,@SergeyA。上次我检查时,Libstdc++ 不支持这个,但它的unordered_map
从 GCC 4.9.0 开始就支持它,OP 似乎有轶事证据表明 libc++ 确实如此(尽管我们甚至不知道是否有 typedef :) 的实例)
- boost::进程间消息队列引发错误
- 将更高的优先级设置为 boost::asio 线程处理进程
- 避免使用 boost::进程间::消息队列创建文件
- BOOST线程:线程还是进程
- Boost进程"系统"功能中的错误处理
- 如何重现 Boost 进程文档提示的死锁?
- 两个并发的 Python 进程可以在 Boost Python 中运行吗?
- Boost.Process - 从具有休眠循环的进程读取
- Boost.进程间内存位置
- 如何确保我们从 boost::child 进程中读取所有行
- 包含字符串的结构的 Boost 进程间向量是否需要特殊的分配器?
- 有没有办法为使用 Boost 生成的进程创建新的控制台窗口
- std::unordered_map 在共享内存中使用 boost:::进程间分配器 - 缺点?
- Growing Boost.使用单个写入器的进程间内存映射文件
- 当一个进程截断 Boost 进程间库创建的共享内存时,进程需要重新映射
- boost::p rocess 如何知道进程何时退出"gracefully or not"?
- boost消息队列线程安全和进程安全吗?
- 使用boost进程间库的phpexec共享内存和Cloudfoundry容器问题
- boost::OSX 上 32 位和 64 位程序之间共享内存中的进程间同步机制(互斥体、条件)
- 如何确保 boost::文件系统::remove 不会尝试删除由其他进程使用的文件