c++ Boost进程间shared_ptr异常

Posted

技术标签:

【中文标题】c++ Boost进程间shared_ptr异常【英文标题】:c++ Boost interprocess shared_ptr exception 【发布时间】:2017-05-29 23:58:41 【问题描述】:

我正在尝试将共享指针(增强进程间)保存在进程间无序映射中作为值。在我的测试程序中,我插入了大约 100 个元素。每个元素都有一个字符串作为键,一个 shared_ptr 作为值。 shared_ptr 是一个复杂数据类型的指针。

第一个元素的创建和插入成功完成。但是,当我为第二个元素创建 shared_ptr 实例时出现异常。我收到以下异常:

错误:boost::interprocess_exception::library_error。 错误代码:错误的文件描述符。 本机错误:0。

我已经粘贴了下面的代码。任何帮助表示赞赏。谢谢。

defs.h

// basic shared memory defs.
#pragma once

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>

namespace bip = boost::interprocess;

namespace ip 

namespace shmem 

  using segment = bip::managed_shared_memory;
  using segment_manager = segment::segment_manager;

  using void_allocator = bip::allocator<void, segment_manager>;
  using char_allocator = bip::allocator<char, segment_manager>;
  using int_allocator = bip::allocator<int, segment_manager>;
  using double_allocator = bip::allocator<double, segment_manager>;
  using size_t_allocator = bip::allocator<size_t, segment_manager>;
  using string = bip::basic_string<char, std::char_traits<char>, char_allocator>;

 // namespace shmem

 // namespace ip

地图值.h

#pragma once
#include <boost/interprocess/smart_ptr/deleter.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
#include <cassert>

#include "defs.h"

namespace ip


template <typename ValueType>
class MapValue

public:
  using MVType = MapValue<ValueType>;
  typedef typename bip::deleter<MVType, shmem::segment_manager> MVDeleter;
  typedef typename bip::managed_shared_ptr<MVType, shmem::segment>::type MapValuePtr;

  MapValue(const shmem::void_allocator&, ValueType value=ValueType(), size_t=0);

  MapValue(const MapValue& other);
  MapValue& operator=(const MapValue& other);
  MapValue(const MapValue&& other) noexcept;
  MapValue& operator=(const MapValue&& other) noexcept;
  void swap(const MapValue& other) noexcept;

  size_t GetTimestamp() const  return mTimestamp; 
  ValueType GetValue() const  return mValue; 

private:
  size_t mTimestamp;
  ValueType mValue;
;

 // namespace ip

map-value.cc

#include "map-value.h"

namespace ip


template <typename ValueType>
MapValue<ValueType>::MapValue(const shmem::void_allocator &void_allocator
                                          , ValueType value, size_t expire_ts)
: mTimestamp(expire_ts)
, mValue(value, void_allocator)



template <typename ValueType>
MapValue<ValueType>::MapValue(const MapValue& other)
: mTimestamp(other.mTimestamp)
, mValue(other.mValue)



template <typename ValueType>
MapValue<ValueType>&
MapValue<ValueType>::operator=(const MapValue& other)

  MapValue tmp(other);
  swap(tmp);
  return *this;


template <typename ValueType>
MapValue<ValueType>::MapValue(const MapValue&& other) noexcept
: mTimestamp(std::move(other.mTimestamp))
, mValue(std::move(other.mValue))



template <typename ValueType>
MapValue<ValueType>&
MapValue<ValueType>::operator=(const MapValue&& other) noexcept

  auto tmp = std::move(other);
  swap(tmp);
  return *this;


template <typename ValueType>
void
MapValue<ValueType>::swap(const MapValue& other) noexcept

  mTimestamp = other.mTimestamp;
  mValue = other.mValue;


template class MapValue<shmem::string>;

 // namespace ip

unorderd_map_master.cc

#include <chrono>
#include <cstdlib>
#include <iostream>
#include <functional>                 //std::equal_to
#include <sstream>
#include <string.h>

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/unordered_map.hpp>    //boost::unordered_map
#include <boost/functional/hash.hpp>  //boost::hash

#include "map-value.h"

using namespace boost::interprocess;
using namespace ip;

int
main ()

  shared_memory_object::remove("MySharedMemory");

  // Create shared memory
  managed_shared_memory segment(create_only, "MySharedMemory", 1024*64);

  // Note that unordered_map<Key, MappedType>'s value_type is 
  // std::pair<const Key, MappedType>, so the allocator must allocate a pair.
  // 
  typedef int  KeyType;
  //typedef size_t  MappedType;
  typedef std::pair<const int, MapValue<shmem::string>::MapValuePtr> ValueType;

  // Typedef the allocator
  typedef allocator<ValueType, shmem::segment_manager> ShmemAllocator;

  // Alias an unordered_map of ints that uses the previous STL-like allocator.
  typedef boost::unordered_map<KeyType, MapValue<shmem::string>::MapValuePtr
                               , boost::hash<KeyType>, std::equal_to<KeyType>
                               , ShmemAllocator> SharedHashMap;

  // Construct a shared memory hash map.
  // Note that the first parameter is the initial bucket count and
  // after that, the hash function, the equality function and the allocator
  SharedHashMap *hashmap = segment.construct<SharedHashMap>("SharedHashMap")      //object name
                               (4                                       // bucket count
                                , boost::hash<KeyType>()                // hash func
                                , std::equal_to<KeyType>()              // equality func
                                , segment.get_allocator<ValueType>());  //allocator instance

  int i;
  std::string test("test");

  using MVString = MapValue<shmem::string>;
  using MVStringPtr = MVString::MapValuePtr;
  using MVStringDeleter = MVString::MVDeleter;
  shmem::void_allocator alloc_inst (segment.get_segment_manager());

  try 
    // Insert data in the hash map
    for (i = 0; i < 100; ++i) 
      // Create a shared pointer in shared memory
      // pointing to a newly created object in the segment
      std::ostringstream ostr;
      ostr << test << i;
      const uint64_t now = std::chrono::duration_cast<std::chrono::microseconds>(
                                  std::chrono::steady_clock::now().time_since_epoch()).count();
      size_t ts = now + 60*1000000;   // 60s from now.

      shmem::string name(ostr.str().c_str(), alloc_inst);
      std::cout << "created name: " << name << '\n';
      MVStringPtr sh_ptr_instance =
          make_managed_shared_ptr(segment.construct<MVString>("MVString")(alloc_inst
                                                                          , name, ts), segment);

      assert(sh_ptr_instance.use_count() == 1);
      std::cout << "created shared_ptr" << '\n';

      hashmap->insert(ValueType(i, sh_ptr_instance));
      std::cout << "Inserting at " << i << ": "
                << "value: " << ostr.str() << ". "
                << "timestamp: " << ts << '\n';
    
  
  catch (const bip::interprocess_exception& e) 
    std::cout << "error: " << e.what() << ". "
              << "error-code: " << strerror(e.get_error_code()) << ". "
              << "error-msg: " << e.get_native_error() << ". " << '\n';
    std::cout << "Error while inserting element #" << (i+1) << '\n';
    shared_memory_object::remove("MySharedMemory");
    std::exit(-1);
  

  std::cout << i << " values inserted into shared memory" << '\n';
  return 0;

unorder_map_slave.cc

#include <cstdlib>
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/unordered_map.hpp>   //boost::unordered_map
#include <functional>      //std::equal_to
#include <boost/functional/hash.hpp> //boost::hash

#include "map-value.h"

using namespace boost::interprocess;
using namespace ip;

int
main (int argc, char *argv[])

  using namespace boost::interprocess;

  int c;
  bool clear_shmem = false;

  while ((c = getopt(argc, argv, "c")) != -1) 
    switch(c) 
      case 'c':
        clear_shmem = true;
        break;
      default:
        std::cout << "Invalid input params to " << argv[0] << '\n';
        break;
    
  

  try
  
    managed_shared_memory segment(open_or_create, "MySharedMemory", 65536);

    // Again the map<Key, MappedType>'s value_type is std::pair<const Key, MappedType>,
        // so the allocator must allocate that pair.
    typedef int  KeyType;
    //typedef size_t  MappedType;
    typedef std::pair<const int, MapValue<shmem::string>::MapValuePtr> ValueType;

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

    // The map
    typedef boost::unordered_map<KeyType, MapValue<shmem::string>::MapValuePtr
                                 , boost::hash<KeyType>, std::equal_to<KeyType>
                                 , ShmemAllocator> SharedHashMap;

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

    // access the map in SHM through the offset ptr
    SharedHashMap::iterator iter;
    offset_ptr<SharedHashMap> m_pmap = segment.find<SharedHashMap>("SharedHashMap").first;

    if (!m_pmap) 
      std::cout << "Shared memory not initalized... Exiting..." << '\n';
      std::exit(-1);
    

    iter = m_pmap->begin();
    std::cout<< "size: " << m_pmap->size();

    using MVString = MapValue<shmem::string>;
    using MVStringPtr = MVString::MapValuePtr;
    using MVStringDeleter = MVString::MVDeleter;

    for (; iter != m_pmap->end(); iter++) 
      MapValue<shmem::string>::MapValuePtr val(iter->second);
      std::cout << "\n " << iter->first << " : "
                << "value: " << val->GetValue() << ". "
                << "timestamp: " << val->GetTimestamp() << '\n';
    

    std::cout<< "\n";
  

  catch (const bip::interprocess_exception& e) 
    std::cout << "error: " << e.what() << ". "
              << "error-code: " << strerror(e.get_error_code()) << ". "
              << "error-msg: " << e.get_native_error() << ". " << '\n';
    shared_memory_object::remove("MySharedMemory");
  

  if (clear_shmem) 
    shared_memory_object::remove("MySharedMemory");
  

  return 0;

【问题讨论】:

请提供minimal reproducible example。 不确定完整示例的含义。我已经提供了所需的完整代码。请将每个代码块保存到单独的文件中(我什至提供了文件名)。之后您可以执行以下操作: g++ -std=c++1y -o umap_master map-value.cc unordered_map_master.cc; g++ -std=c++1y -o umap_slave map-value.cc unordered_map_slave.cc;你可以运行'umap_master',你会看到错误。不知道你为什么投反对票?如果您需要更多信息,就不能在不投反对票的情况下要求更多信息吗? 我确信您的示例确实是完整且可验证的。第一个词是关键字:Minimal。这意味着您必须提供一小段仍能重现问题的代码。这也是调试非常奇怪的错误的一种超级有效的方法。要么 1)编写一个小程序并尝试重现问题,以便您考虑的事情更少,或者 2)删除一些代码;看看问题是否仍然存在。重复直到您不再看到错误,此时您知道错误来自您删除的最后一些内容。 确实很小。我的问题是为复杂数据类型创建一个共享指针,该指针可以作为值插入到地图中。这个例子就是这样,仅此而已。也许,我可以删除 slave.cc 代码,因为它不需要重现问题。但是,对于一个进程间示例,我认为最好同时提供两者(因为关于 SO 的每个进程间问题都这样做了)。人们来 SO 是为了得到他们问题的答案。您甚至没有花时间查看或回答问题,而是走上了对任何人都没有帮助的不必要的切线。 【参考方案1】:

我已经为自己找到了答案。看起来给共享指针的名称字符串必须是唯一的。

MVStringPtr sh_ptr_instance =
       make_managed_shared_ptr(segment.construct<MVString>("MVString")(alloc_inst, name, ts), segment);

例如,上面代码中的字符串“MVString”必须是唯一的。我看到了错误,因为我正在创建多个同名的共享指针。使名称字符串唯一解决了我的问题。

【讨论】:

以上是关于c++ Boost进程间shared_ptr异常的主要内容,如果未能解决你的问题,请参考以下文章

python嵌入C++,函数返回shared_ptr(pybind11/boost_python)

c++ boost进程间交换(复制)非共享和共享字符串向量

如何使用 g++ 在 Linux 上使用 boost/shared_ptr.hpp 编译 c++ 程序

boost 在c++中是啥用

使用 boost::shared_ptr 访问静态成员变量

将派生类型的对象从 python 传递到 C++ 函数时会出现 Boost Python 运行时错误,该函数期望将 shared_ptr 传递给基类型