我有以下代码模式:
class A {
double a, b, c;
...
};
class B {
map<int, A> table; // Can have maximum of MAX_ROWS elements.
...
};
class C {
B entries;
queue<int> d;
queue<int> e;
...
};
现在我想在共享内存中存储C类型的对象,以便不同的进程可以追加,更新和读取它。我怎样才能做到这一点? (注意:我知道如何在共享内存中存储一个固定大小的简单C数组。另外,请记住B.table可能有任意条目。
答案 0 :(得分:17)
使用boost::interprocess,此库会公开此功能。
编辑:以下是您需要做的一些更改:
该示例已经定义了将从共享内存块分配的分配器,您需要将其传递给map
和queue
。这意味着您必须更改定义:
class B
{
map<int, A, less<int>, MapShmemAllocator> table;
// Constructor of the map needs the instance of the allocator
B(MapShmemAllocator& alloc) : table(less<int>(), alloc)
{ }
}
对于queue
,这有点复杂,因为它实际上只是一个适配器,因此您需要将实际的实现类作为模板参数传递:
typedef queue<int, deque<int, QueueShmemAllocator> > QueueType;
现在,您的班级C
略有变化:
class C
{
B entries;
QueueType d, e;
C(MapShmemAllocator& allocM, QueueShmemAllocator& allocQ) : entries(allocM), d(allocQ), e(allocQ)
{ }
}
现在,从分部管理器,使用分配器构建C
的实例。
C *pC = segment.construct<C>("CInst")(allocM_inst, allocQ_inst);
我认为应该这样做。注意:您需要提供两个分配器(一个用于queue
,一个用于map
),不确定是否可以从同一个段管理器构造两个分配器,但我不明白为什么不这样做。
答案 1 :(得分:3)
这可能很棘手。首先,你需要一个自定义分配器:Boost
Interprocess有一个,我从它开始。在你的确切例子中,
这可能就足够了,但更一般地说,你需要确保这一点
所有子类型也使用共享内存。因此,如果你想要映射
一个字符串,该字符串也需要一个自定义分配器,这意味着
它的类型与std::string
不同,你不能复制或
从std::string
分配给它(但你可以使用两个迭代器
构造函数,例如:
typedef std::basic_string<char, std::char_traits<char>, ShmemAllocator> ShmemString;
std::map<ShmemString, X, std::less<ShmemString>, ShmemAllocator> shmemMap;
访问次数如下:
shmemMap[ShmemString(key.begin(), key.end())] ...
当然,您定义的任何进入地图的类型也必须使用
任何分配的共享内存:Boost Interprocess有一个
offset_ptr
这可能对此有所帮助。
答案 2 :(得分:2)
在共享内存中构建和使用STL对象并不棘手(特别是使用boost :: interprocess包装器)。当然,你也应该使用同步机制(也不是boost&named #mutex的问题)。
真正的挑战是保持STL对象在共享内存中的一致性。基本上,如果其中一个进程在一个不好的时间点崩溃,它会让其他进程出现两个大问题:
锁定的互斥锁(可以使用棘手的PID到互斥映射,强大的互斥锁(在任何可用的地方),定时的互斥锁等来解析。
处于不一致状态的STL对象(例如,擦除()过程中的半更新地图结构)。通常,这是不可恢复的,您需要从头开始在共享内存区域中销毁和重构对象(可能也会杀死所有其他进程)。您可以尝试拦截应用程序中的所有可能的外部信号,并且交叉手指希望一切顺利,并且过程永远不会在糟糕的时刻失败。
在决定在系统中使用共享内存时,请记住这一点。