首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Boost::Interprocess在进程间共享std::string

使用Boost::Interprocess在进程间共享std::string
EN

Stack Overflow用户
提问于 2022-10-12 08:00:23
回答 1查看 46关注 0票数 2

我正在跟踪这个Boost::进程间指南。我有一个以std::string为成员的结构,我用std::string作为键值创建了这个结构的multimap。我可以用生产者代码从结构中访问std::string。但是,当我试图访问消费者代码中的同一个std::string成员时,我就得到了核心转储。

有人能帮我吗。提前谢谢。我给出的代码如下:

生产者代码:

代码语言:javascript
运行
复制
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>

struct temp
{
    int x;
    int y;
    std::string name;
};

    int main ()
{
    using namespace boost::interprocess;
   
    try
    {
        shared_memory_object::remove("MySharedMultimap");

        managed_shared_memory segment
         (create_only
         ,"MySharedMultimap" //segment name
         ,65536);          //segment size in bytes


        typedef std::string KeyType;
        typedef struct temp MappedType;
        typedef std::pair<const std::string, struct temp> ValueType;

        typedef allocator< ValueType, managed_shared_memory::segment_manager>
            ShmemAllocator;


        typedef multimap<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> MyMultimap;

        //Initialize shared memory STL-compatible allocator
        const ShmemAllocator alloc_inst (segment.get_segment_manager());

          //Construct a shared memory
        MyMultimap *mymultimap =
             segment.construct<MyMultimap>("MyMultimap") //object name
                                        (alloc_inst);//first ctor parameter

        std::string s = "key1";
        mymultimap->insert(std::pair<KeyType, MappedType>(s, t1));
    }
    catch(...)
    {
          shared_memory_object::remove("MySharedMultimap");
          throw;
    }
}

消费者代码:

代码语言:javascript
运行
复制
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>



struct temp
{
        int x;
        int y;
        std::string name;
};

    int main ()
   {
       using namespace boost::interprocess;
   
   try
   {
      managed_shared_memory segment
         (open_only
         ,"MySharedMultimap");  //segment name


      typedef std::string KeyType;
      typedef struct temp MappedType;
      typedef std::pair<const std::string, struct temp> ValueType;

      //Alias an STL compatible allocator of ints that allocates ints from the managed
      //shared memory segment.  This allocator will allow to place containers
      //in managed shared memory segments
      typedef allocator<ValueType , managed_shared_memory::segment_manager>
         ShmemAllocator;

      //Alias a vector that uses the previous STL-like allocator
      typedef multimap< KeyType, MappedType, std::less<KeyType>,  ShmemAllocator> MyMultimap;

      //Find the vector using the c-string name
      MyMultimap *mymultimap = segment.find<MyMultimap>("MyMultimap").first;

      std:: cout << " multimap size size : " << mymultimap->size() << std::endl;


      for(auto i = mymultimap->begin(); i != mymultimap->end(); ++i)
      {
        std::cout << i->first << std::endl;      // core dump ( as we are accessing std::string )

        std::cout << i->second.x << std::endl;  // works fine

        std::cout << i->second.name << std::endl;   // core dump ( as we are accessing std::string )
      }
    }
    catch(...){
      shared_memory_object::remove("MySharedMultimap");
      throw;
    }
}
EN

回答 1

Stack Overflow用户

发布于 2022-10-12 11:39:32

您需要使用共享内存分配器。你已经有了,为什么不使用它们呢?

首先,我将您的测试程序简化并组合成一个:住在ColiruNote,这仍然存在同样的问题。

解决问题

您需要使用带有共享内存分配器的字符串:

代码语言:javascript
运行
复制
namespace bip = boost::interprocess;
using Segment = bip::managed_shared_memory;
using Mgr     = Segment::segment_manager;

template <typename T>
using Alloc = bip::allocator<T, Mgr>;

using String = bip::basic_string<char, std::char_traits<char>, Alloc<char>>;

现在,用它:

代码语言:javascript
运行
复制
struct temp {
    int    x;
    int    y;
    String name;
};
using MyMultimap = Multimap<String, temp>;

这意味着您还必须转换"more data"

代码语言:javascript
运行
复制
// assume sa = String::allocator_type     sa(segment.get_segment_manager())

String more_data("more data", sa);
m.insert({String("key", sa), temp{1, 2, more_data}});

工作,住在Coliru,打印:

代码语言:javascript
运行
复制
 multimap size size : 1
key
1
more data

解决那些烦人的分配器?

那是很多手动分配器的杂耍。使用作用域分配器可以减少这样的情况:

代码语言:javascript
运行
复制
template <typename T>
using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;

现在你可以写:

代码语言:javascript
运行
复制
m.emplace("key", temp{1, 2, String("more data", sa)});

要将分配器传播到temp::name成员,需要使temp分配器具有感知性。multimap不是一个适合用它来展示这一点的例子,因为它的接口并没有真正地使用它。 为了完整起见,以下是它的外观草图: struct {使用String = Shared::String;使用allocator_type = String::allocator_type;temp(temp &)=默认;temp (temp&)=String::allocator_type;temp(temp const& rhs,allocator_type a):x(rhs.x),y(rhs.y),name(rhs.name.data(),rhs.name.size(),a) {} temp(temp& rhs,allocator_type a):temp(std::move(rhs)) { if (a = name.get_allocator()) name = String(name.data(),name.size(),a;}模板temp(int x,int y,char const* name,Alloc a= {}):x(x),y(y),name(name,a) {} int x;int y;String name;};

异构查找

比你的问题早一步:你可能会想要m.find("key"),或者.lower_bound.upper_bound.equal_range。为了避免相同的分配器混乱和低效率地分配临时人员,如下所示:

代码语言:javascript
运行
复制
String::allocator_type sa(m.get_segment_manager());
auto r = m.equal_range(String("key", sa));

使用透明的比较:

代码语言:javascript
运行
复制
using MyMultimap = Multimap<String, temp, std::less<>>;

现在你可以“只是”写:

代码语言:javascript
运行
复制
// key lookup:
for (auto& [k, v] : boost::make_iterator_range(m.equal_range("key"))) {
    std::cout << k << "\n";
    std::cout << v.x    << "\n";
    std::cout << v.name << "\n";
}

全演示

住在Coliru

代码语言:javascript
运行
复制
#include <boost/container/map.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/string.hpp>
#include <boost/container/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>

namespace bip = boost::interprocess;
namespace Shared {
    namespace bc = boost::container;

#ifndef COLIRU
    using Segment = bip::managed_shared_memory;
#else
    using Segment = bip::managed_mapped_file;
#endif

    using Mgr    = Segment::segment_manager;
    template <typename T>
    using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;

    template <typename K, typename V, typename Cmp = std::less<K>>
    using Multimap = bc::multimap<K, V, Cmp, Alloc<std::pair<K const, V>>>;

    using String = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;

    static auto Remove = bip::shared_memory_object::remove;
} // namespace Shared

struct temp {
    using String         = Shared::String;
    using allocator_type = String::allocator_type;

    temp(temp const&) = default;
    temp(temp&&)      = default;

    temp(temp const& rhs, allocator_type a)
        : x(rhs.x)
        , y(rhs.y)
        , name(rhs.name.data(), rhs.name.size(), a) {}

    temp(temp&& rhs, allocator_type a) : temp(std::move(rhs)) {
        if (a != name.get_allocator())
            name = String(name.data(), name.size(), a);
    }

    template <typename Alloc>
    temp(int x, int y, char const* name, Alloc a = {})
        : x(x)
        , y(y)
        , name(name, a) {}

    int    x;
    int    y;
    String name;
};

int main(int argc, char** /*unused*/) {
    using namespace Shared;

    using MyMultimap        = Multimap<String, temp, std::less<>>;
    auto constexpr shm_name = "MySharedMemory";
    auto constexpr map_name = "MyMultimap";

    try {
        if (argc > 1) { // Producer
            Remove(shm_name);
            Segment segment(bip::create_only, shm_name, 65536);
            auto*   sm = segment.get_segment_manager();
            auto&   m  = *segment.construct<MyMultimap>(map_name) // object name
                       (sm); // first ctor parameter

            temp&& v{1, 2, "more data", sm};
            m.emplace("key", v);
        } else { // Consumer
            Segment segment(bip::open_only, shm_name);
            auto& m = *segment.find<MyMultimap>(map_name).first;

            std::cout << " multimap size size : " << m.size() << "\n";

            // key lookup:
            for (auto& [k, v] : boost::make_iterator_range(m.equal_range("key"))) {
                std::cout << k << "\n";
                std::cout << v.x    << "\n";
                std::cout << v.name << "\n";
            }
        }
    } catch (...) {
        // remove(name);
        throw;
    }
}

与G.

代码语言:javascript
运行
复制
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -lrt -DCOLIRU
./a.out producer
./a.out

打印

代码语言:javascript
运行
复制
 multimap size size : 1
key
1
more data
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74038390

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档