【问题标题】:How to store stl objects in shared memory (C++)?如何将 stl 对象存储在共享内存(C++)中?
【发布时间】:2012-08-25 23:46:11
【问题描述】:

我有以下代码模式:

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

【问题讨论】:

  • 这并不容易。对于所有知道共享内存的容器,您需要一个特殊的分配器。在 C++11 中,由于有状态分配器,这更容易实现,但无论如何它都不是微不足道的。
  • 我正在使用 i686-apple-darwin11-llvm-g++-4.2。你们需要有关特定编译器或平台的更多信息吗?

标签: c++ stl shared-memory


【解决方案1】:

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

【讨论】:

【解决方案2】:

这可能很棘手。对于初学者,您需要一个自定义分配器: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 这可能会有所帮助。

【讨论】:

    【解决方案3】:

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

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

    • 锁定的互斥锁(可以使用棘手的 PID 到互斥锁映射、强大的互斥锁(如果可用)、定时互斥锁等来解决。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-10
      • 2010-12-29
      相关资源
      最近更新 更多