【问题标题】:Program crashes when trying to access the inner map尝试访问内部地图时程序崩溃
【发布时间】:2014-10-21 20:11:30
【问题描述】:

以下是一个小型读写器程序。写入器将值写入映射映射,写入成功。 还有一个叫做 reader 的进程读取 SHM 的内容,reader 读取外部 map 的 key 没有问题,但是如果我们尝试访问内部 map 的内容,它会崩溃。 我检查了容器大小,它为 case1 打印了 2,这很好,因为内部映射包含键“case1”的 2 个元素。

但是,当我尝试访问内部地图时,程序崩溃,是我访问内部地图的方式不正确。以下是我正在使用的代码 sn-ps。

ShmTypedefs.h

#ifndef __SHM_TYPE_DEFS__
    #define __SHM_TYPE_DEFS__
    #include <boost/interprocess/allocators/allocator.hpp>
    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/containers/string.hpp>
    #include <boost/interprocess/containers/map.hpp>

    //the strings also need to be assigned from the shared memory
    typedef boost::interprocess::allocator<void, boost::interprocess::managed_shared_memory::segment_manager> VoidAllocator;
    typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
    typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> SharedString;

    //Note that map<Key, MappedType>'s value_type is std::pair<const Key, MappedType>,
    //so the allocator must allocate that pair.
    typedef SharedString KeyType;
    typedef boost::interprocess::map<SharedString, int>  MappedType;
    typedef std::pair<const KeyType, MappedType> ValueType;

    //allocator for the string
    typedef boost::interprocess::allocator<SharedString, boost::interprocess::managed_shared_memory::segment_manager> StringAllocator;
    //allocator of for the map.
    typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
    typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
    //third parameter argument is the ordering function is used to compare the keys.
    typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> MySHMMap;
#endif

writer.cxx

    #include <boost/interprocess/containers/map.hpp>
    #include <functional>
    #include <utility>
    #include <ShmTypedefs.h>
    #include <iostream>
    using namespace boost::interprocess;

    int main ()
    {
      // remove earlier existing SHM
      shared_memory_object::remove("SharedMemoryName");

      // create new
      managed_shared_memory segment(create_only,"SharedMemoryName",65536);

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

      //third parameter argument is the ordering function is used to compare the keys.
      typedef map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> MySHMMap;

      //offset ptr within SHM for map
      //After construction m_pmap will contain the only object that has been consturcted in pmap[0]
      //If we construct another object it will goto pmap[1]

      offset_ptr<MySHMMap> m_pmap = segment.construct<MySHMMap>("MySHMMapName")(std::less<SharedString>(), alloc_inst);

      //Insert data in the map
      StringAllocator string_alloc_instance( segment.get_segment_manager() );

      SharedString key("case1", string_alloc_instance );
      SharedString inner_map_key("inner_case1", string_alloc_instance );

      SharedString key1("case2", string_alloc_instance );
      SharedString inner_map_key1("inner_case2", string_alloc_instance );

      SharedString inner_map_key2("inner_case3", string_alloc_instance );

      m_pmap[0][key][inner_map_key] = 2030;
      m_pmap[0][key1][inner_map_key1] = 2031;
      m_pmap[0][key][inner_map_key2] = 2034;
      std::cout<<"\n "<<m_pmap[0][key][inner_map_key]<< std::endl;
      std::cout<<"\n "<<m_pmap[0][key1][inner_map_key1]<< std::endl;
      return 0;
    }

reader.cxx

 #include <boost/interprocess/containers/map.hpp>
#include <functional>
#include <utility>
#include <iostream>
#include <ShmTypedefs.h>

using namespace boost::interprocess;

int main ()
{

  try
  {

    managed_shared_memory segment(open_or_create, "SharedMemoryName",65536);

    int size= segment.find<MySHMMap>("MySHMMapName").second;
    std::cout<< "size of map " << size << std::endl;
    offset_ptr<MySHMMap> m_pmap = segment.find<MySHMMap>("MySHMMapName").first;
    MySHMMap :: iterator iter = m_pmap[0].begin();
    MySHMMap :: iterator iter_end = m_pmap[0].end();
    for(; iter != iter_end; ++iter ) {
      std::cout<<"\n "<< iter->first<<std::endl;
      if( iter->first == "case1" ) {
         MappedType::iterator iti = (iter->second).begin();

         MappedType::iterator iti_end = (iter->second).end();
         for( ;iti != iti_end; ++iti ) {
         std::cout << "symbol " << iti->first << " time " << iti->second << std::endl;
          }
      }
    }
  }
  catch(std::exception &e) {
    std::cout<<" error  " << e.what() <<std::endl;
    shared_memory_object::remove("SharedMemoryName");
  }
  return 0;
}

堆栈跟踪:

运行程序时的输出 =>

   droy@apdeva01 shmmapofmap> ./bin/reader
    size of map 1
    case1
    Matched case 1
    Size of the inner container is 2 units
    Segmentation fault (core dumped)

核心输出:

(gdb) bt
#0  get_right () at /home/dev/build/third_party/64-rhel5/boost_1_47_0/include/boost/intrusive/detail/rbtree_node.hpp:130
#1  next_node () at /home/dev/build/third_party/64-rhel5/boost_1_47_0/include/boost/intrusive/detail/tree_algorithms.hpp:441
#2  next_node () at /home/dev/build/third_party/64-rhel5/boost_1_47_0/include/boost/intrusive/rbtree_algorithms.hpp:353
#3  operator++ () at /home/dev/build/third_party/64-rhel5/boost_1_47_0/include/boost/intrusive/detail/tree_node.hpp:119
#4  prot_incr ()
    at /home/dev/build/third_party/64-rhel5/boost_1_47_0/include/boost/interprocess/containers/container/detail/tree.hpp:326
#5  operator++ ()
    at /home/dev/build/third_party/64-rhel5/boost_1_47_0/include/boost/interprocess/containers/container/detail/tree.hpp:395
#6  __distance<boost::container::containers_detail::rbtree<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > >, std::pair<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > const, int>, boost::container::containers_detail::select1st<std::pair<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > const, int> >, std::less<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > >, std::allocator<std::pair<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > const, int> > >::iterator> ()
    at /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_iterator_base_funcs.h:79
#7  distance<boost::container::containers_detail::rbtree<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interproce---Type <return> to continue, or q <return> to quit---
ss::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > >, std::pair<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > const, int>, boost::container::containers_detail::select1st<std::pair<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > const, int> >, std::less<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > >, std::allocator<std::pair<boost::container::basic_string<char, std::char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0ul>, boost::interprocess::iset_index> > > const, int> > >::iterator> ()
    at /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_iterator_base_funcs.h:114
#8  main () at /home/user/droy/src/quotes/debshmutils/shmmapofmap/src/reader.cxx:33

【问题讨论】:

  • 您的代码太复杂,无法发现可能有问题的地方,您能简化为 MWE 吗? (见stackoverflow.com/help/mcve
  • 看起来你想读取一个不存在的节点
  • @Maciej 为什么内图的尺寸会是 2 呢?
  • 这个例子很大,但我看到你保存了迭代器。你确定执行距离函数时它们指向的元素仍然存在吗?
  • 用代码行 MappedType::iterator iti = (iter->second).begin(), MappedType::iterator iti_end = (iter->second).end();我没有看到迭代器失效的可能性,映射的映射在共享内存中,这可能是导致问题的原因吗?

标签: c++ boost stl


【解决方案1】:

您的映射类型:

typedef boost::interprocess::map<SharedString, int>  MappedType;

不在共享内存中分配其节点。因此,外部映射中的指针指向本地堆上的地址,因此在读取端不存在(或未定义)。

这里是固定作者 Live On Coliru。相关类型定义:

typedef boost::interprocess::allocator<std::pair<const SharedString, int>, boost::interprocess::managed_shared_memory::segment_manager > InnerMapAlloc;
typedef boost::interprocess::map<SharedString, int, std::less<SharedString>, InnerMapAlloc>  MappedType;

输出:

case1, inner_case1, 2030
case1, inner_case2, 2031
case1, inner_case3, 2034

注意:

  • 您在 main 中的 MySHMMap 定义存在冲突
  • 这是非常笨拙的代码。

    InnerMapAlloc inner_map_alloc_instance(segment.get_segment_manager());
    
    {
        MappedType& tmp = m_pmap->emplace(key, MappedType(inner_map_alloc_instance)).first->second;
        tmp.emplace(inner_map_key, 2030);
        tmp.emplace(inner_map_key2, 2034);
    }
    
    {
        MappedType& tmp = m_pmap->emplace(key, MappedType(inner_map_alloc_instance)).first->second;
        tmp.emplace(inner_map_key1, 2031);
    }
    
    for (auto const& outer : *m_pmap)
        for (auto const& inner : outer.second)
            std::cout << outer.first << ", " << inner.first << ", " << inner.second << "\n";
    

    考虑疯狂地简化数据结构和/或将其抽象到隐藏丑陋的适当类中

    更新发布了PoC based on Boost MultiIndex

  • 据我所知,

    // After construction m_pmap will contain the only object that has been constructed in pmap[0]
    // If we construct another object it will goto pmap[1]
    

    我从来没有听说过这个。您能指出说明这一点的文档吗?

【讨论】:

  • 嗯。我应该有一个 MappedType 的分配器,就像 SharedString 一样。让我试试看。
  • @deb 我已经(为了乐趣和荣耀)为您修复了作者方面的问题,请参阅更新。我认为您将自己淹没在共享分配的沼泽中。你能重新考虑一下设计吗?
  • @deb 以及更多乐趣:a cleaned up version with Boost Multi Index。我认为这更具可读性和可维护性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
相关资源
最近更新 更多