c++ 在对象的构造函数中打开Boost进程间段

xn1cxnb4  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(111)

我在一个进程中的Boost Interprocess managed_shared_memory中创建了一个map<int, vector<int>>,然后想在另一个进程中打开它并继续写入。另一个进程试图在对象Communication的构造函数中打开共享内存,然后给出一个方法addData(int _data)
范例:

// Typedefs for shared data structures

using boost::interprocess;
using std::pair;
using std::scoped_allocator_adaptor;

typedef managed_shared_memory::segment_manager man;

typedef allocator <int , man> Int_Allocator;
typedef vector <int, Int_Allocator> Int_Vector;

typedef pair <const int, Int_Vector> Int_Vector_Map_Type;
typedef scoped_allocator_adaptor <allocator<Int_Vector_Map_Type, man>> Int_Vector_Map_Type_Allocator;
typedef map <int, Int_Vector, std::less<int>, Int_Vector_Map_Type_Allocator> Int_Vector_Map;
// Let's call this process 'parent'

managed_shared_memory segment(create_only, "Shared");
Int_Vector_Map_Type_Allocator alloc = segment.get_segment_manager();
segment.construct<Int_Vector_Map>("Map")(std::less<int>(), alloc);
// 'child' process

class Communciation{
    Int_Vector_Map* map;

public:
    Communication{
        managed_shared_memory segment(open_only, "Shared");
        map = segment.find<Int_Vector_Map>("Map").first;
    }
    void addData(int _key, int _value){
        if(map->size() == 0 || map->find(_key) == map->end(){
            managed_shared_memory segment(open_only, "Shared");
            Int_Allocator alloc = segment.get_segment_manager();
            map->insert(Int_Vector_Map_Type(_key, Int_Vector(alloc)));
        } // create the vector and its allocator, otherwise runtime error

        map->at(_key).push_back(_value);
    }
}

这是一个分解的例子,但我没有看到即时错误。当试图运行此代码时,我得到运行时错误“未处理的异常:EXCEPTION_ACCESS_VIOLATION阅读地址(...)"。将addData(...)方法更改为:

void addData(int _key, int _value){
    managed_shared_memory segment(open_only, "Shared");
    map = segment.find<Int_Vector_Map>("Map").first;

    if(map->size() == 0 || map->find(_key) == map->end(){
        Int_Allocator alloc = segment.get_segment_manager();
        map->insert(Int_Vector_Map_Type(_key, Int_Vector(alloc)));
    } // create the vector and its allocator, otherwise runtime error

    map->at(_key).push_back(_value);
}


也就是说,每次调用都打开map解决了这个问题,但在我的情况下并不适用,因为我希望能够在每帧中多次调用此方法,而不会对fps产生太大影响。
这个问题的原因是什么,是否可以使用所描述的boost的interprocess?

**编辑:**对于添加的上下文,'child'进程正在另一个进程中运行,我在其中注入了一个dll。

mo49yndu

mo49yndu1#

答案有很多组成部分:

  • 使用简化的类型别名
  • 必须保持Map状态,因此您必须将其作为类中的成员(或具有更长的生存期)
  • 分配器构造只有在始终使用有作用域的分配器并且插入使用分配器构造时才会发生(例如emplace方法)

我有很好的使用Boost Container实现的经验,所以让我们展示一下。

简化类型别名

// Typedefs for shared data structures
namespace bip = boost::interprocess;

namespace Shared {
    namespace bc  = boost::container;
    using Segment = bip::managed_shared_memory;
    using Mgr     = Segment::segment_manager;

    template <typename T> using Alloc  = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;
    template <typename T> using Vector = bc::vector<T, Alloc<T>>;
    template <typename K, typename V, typename Cmp = std::less<K>, typename P = std::pair<K const, V>>
    using Map = bc::map<K, V, Cmp, Alloc<P>>;
} // namespace Shared

字符串
现在你可以简单地说:

using IVMap = Shared::Map<int, Shared::Vector<int>>; // Int_Vector_Map


它将扩展到正确的比较器,分配器等集合。

生命周期

要从构造函数构造段,您需要使用初始化器列表。例如:

class Communication {
  public:
    Communication() //
        : segment_{bip::open_only, "Shared"}
        , map_(*segment_.find<IVMap>("Map").first) {}

    void addData(int key, int value);

  private:
    Shared::Segment segment_;
    IVMap&          map_;
};

Emplace

要插入新元素,请像这样实现addData

void addData(int key, int value) {
    auto it = map_.find(key);

    if (it == map_.end())
        it = map_.emplace(key).first;

    it->second.push_back(value);
}


请注意,段只是存在。请注意,分配器是由于作用域分配器适配器与emplace构造的组合而传播的。

编辑很遗憾我无法编译emplace。我肯定我错过了一些琐碎的东西,但我已经解决了它,比如:

if (it == map_.end()) {
    IVMap::mapped_type v(map_.get_allocator());
    it = map_.emplace(key, std::move(v)).first;
}

现场演示

Live On Coliru

#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <set>

// Typedefs for shared data structures
namespace bip = boost::interprocess;

namespace Shared {
    namespace bc  = boost::container;
#ifdef COLIRU // online compiler
    using Segment = bip::managed_mapped_file;
#else
    using Segment = bip::managed_shared_memory;
#endif
    using Mgr     = Segment::segment_manager;

    template <typename T> using Alloc  = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;
    template <typename T> using Vector = bc::vector<T, Alloc<T>>;
    template <typename K, typename V, typename Cmp = std::less<K>, typename P = std::pair<K const, V>>
    using Map = bc::map<K, V, Cmp, Alloc<P>>;
} // namespace Shared

using IVMap = Shared::Map<int, Shared::Vector<int>>; // Int_Vector_Map

class Communication {
  public:
    Communication() //
        : segment_{bip::open_only, "Shared"}
        , map_(*segment_.find<IVMap>("Map").first) {}

    void addData(int key, int value) {
        auto it = map_.find(key);

        if (it == map_.end()) {
            IVMap::mapped_type v(map_.get_allocator());
            it = map_.emplace(key, std::move(v)).first;
        }

        it->second.push_back(value);
    }

    auto const& get() const { return map_; }

  private:
    Shared::Segment segment_;
    IVMap&          map_;
};

#include <fmt/ranges.h>
#include <functional>
#include <random>
static auto vals = bind(std::uniform_int_distribution(100, 999), std::mt19937{std::random_device{}()});

int main(int argc, char** argv) {
    auto const args = std::set<std::string_view>(argv + 1, argv + argc);

    if (args.contains("parent")) {
        Shared::Segment seg{bip::open_or_create, "Shared", 10 << 10};
        seg.find_or_construct<IVMap>("Map")(seg.get_segment_manager());
    }

    if (args.contains("child")) {
        Communication comm;

        for (unsigned n = 10; n--;) {
            auto v = vals();
            comm.addData(v / 100, v);
        }

        fmt::print("After insertion:\n - {}\n", fmt::join(comm.get(), "\n - "));
    }
}


印刷

+ ./a.out parent
+ ./a.out child
After insertion:
 - (1, [155, 170])
 - (2, [248])
 - (4, [418])
 - (5, [542, 562])
 - (6, [642, 674, 659])
 - (7, [783])
+ ./a.out child
After insertion:
 - (1, [155, 170, 143, 130])
 - (2, [248, 222])
 - (3, [325])
 - (4, [418, 428])
 - (5, [542, 562, 556])
 - (6, [642, 674, 659, 671])
 - (7, [783, 793, 733, 745])
+ ./a.out child
After insertion:
 - (1, [155, 170, 143, 130])
 - (2, [248, 222])
 - (3, [325, 320, 362])
 - (4, [418, 428, 486, 437])
 - (5, [542, 562, 556])
 - (6, [642, 674, 659, 671, 695, 609])
 - (7, [783, 793, 733, 745, 786, 777, 793])
 - (9, [995])


现场演示本地:

相关问题