如何在共享内存(C++)中存储stl对象

How to store stl objects in shared memory (C++)?

本文关键字:存储 stl 对象 C++ 共享 内存      更新时间:2023-10-16

我有以下代码模式:

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可能有任意条目。

使用boost::interprocess,这个库公开了这个功能。

编辑:以下是您需要做的一些更改:

该示例已经定义了一个分配器,该分配器将从共享内存块进行分配,您需要将其传递给mapqueue。这意味着你必须改变你的定义:

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),不确定是否可以从同一个段管理器构造两个分配器,但我不知道为什么不能。

在共享内存中构建和使用STL对象并不棘手(尤其是使用boost::interprocess包装器)。当然,您还应该使用同步机制(boost的named_mutex也没有问题)。

真正的挑战是在共享内存中保持STL对象的一致性。基本上,如果其中一个进程在一个糟糕的时间点崩溃,就会给其他进程留下两个大问题:

  • 锁定的互斥(可以使用棘手的PID到互斥映射、健壮的互斥(只要可用)、定时互斥等来解决)

  • STL对象处于不一致状态(例如,擦除()过程中的半更新映射结构)。一般来说,这是不可恢复的,您需要从头开始销毁并重新构造共享内存区域中的对象(可能还会杀死所有其他进程)。你可以尝试拦截应用程序中所有可能的外部信号,并祈祷一切顺利,处理过程永远不会在糟糕的时刻失败。

在决定在系统中使用共享内存时,请记住这一点。

UPD:检查shmaps(https://github.com/rayrapetyan/shmaps)项目,以了解事情应该如何运作。

这可能很棘手。首先,您需要一个自定义分配器:BoostInterprocess有一个,我从它开始。在你的确切例子中,这可能已经足够了,但更一般地说,您需要确保所有子类型也使用共享内存。因此,如果您想从一个字符串,该字符串还需要一个自定义分配器,这意味着它的类型与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具有CCD_ 10,这可能在这里有所帮助。