使用boost :: interprocess :: shared_ptr共享生命周期交叉进程

时间:2015-05-28 11:51:13

标签: c++ boost shared-ptr boost-interprocess

我尝试使用boost :: interprocess以在进程之间共享数据,并利用shared_ptr进行生命周期管理。我有一张驻留在共享内存中的地图,两个进程应该访问它。

    boost::shared_ptr<boost::interprocess::managed_mapped_file> segment =
          boost::make_shared<boost::interprocess::managed_mapped_file>
                 (boost::interprocess::open_or_create,
                  "./some-mmap.txt", //file name
                  65536);           //segment size in bytes

    pair_allocator_type alloc_inst(segment->get_segment_manager());

    elements = boost::interprocess::make_managed_shared_ptr(
            segment->find_or_construct<map_type>("elements")
            (std::less<IdType>(), alloc_inst),
            *segment
    );

在我有一个测试程序中,父和子进程基本上都使用上面的代码。因此,它们使用相同的底层文件,共享对象的相同名称(&#34;元素&#34;),相同的类型等。

但是,我注意到只要子进程死掉,集合的大小就会降到0.奇怪。我进行了调查,似乎它与elements的破坏有关(当这个共享指针超出范围时)。每当elements超出范围时,底层集合的大小就会变为0。

我还看到elements在父级和子级进程中都有use_count 正好1 。对于有意义的家长,但我不知道为什么孩子会这样。我的假设是,当Child进程终止时,use_count将降为0,然后清除集合。

我想要的是,当Child进程终止时,不会销毁指向的对象(map)。我不应该假设哪些流程是活跃的,哪些不是。

  • 我是否以错误的方式初始化boost::interprocess::shared_ptr
  • 我完全错过了这个指针的语义 - &gt;是仅用于在一个流程中管理共享内存对象生命周期而不是跨流程?
  • 如何在进程间共享use_count的shared_ptr?

编辑 - 有关收集的说明

elementsboost::interprocess::map,它将某个IdType映射到共享内存共享指针ShmemType。当Child进程终止时,elements的大小会降为0。

typedef boost::interprocess::managed_mapped_file::segment_manager segment_manager_type;
typedef std::pair<const IdType, ShmemType::pointer_type> pair_type;
typedef boost::interprocess::allocator<pair_type, segment_manager_type> pair_allocator_type;
typedef boost::interprocess::map<IdType, ShmemType::pointer_type, std::less<IdType>, pair_allocator_type> map_type;

编辑 - 来自提升文档的示例

我从增强文档中提取了示例并对其进行了扩展,以找出原始问题的根本原因。

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <string>
#include <cstdlib> //std::system

using namespace boost::interprocess;

typedef allocator<int, managed_mapped_file::segment_manager>  ShmemAllocator;
typedef vector<int, ShmemAllocator> MyVector;

#include <iostream>

//Main function. For parent process argc == 1, for child process argc == 2
int main(int argc, char *argv[])
{
   if(argc == 1){ //Parent process

      //Create a new segment with given name and size
       managed_mapped_file segment(open_or_create, "./a_MySharedMemory.txt", 65536);

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

//      MyVector* elements = segment.find_or_construct<MyVector>("some-vector")      //object name
//                      (alloc_inst);
       typedef boost::interprocess::managed_shared_ptr<MyVector, boost::interprocess::managed_mapped_file>::type map_pointer_type;

        map_pointer_type elements = boost::interprocess::make_managed_shared_ptr(
                segment.find_or_construct<MyVector>("some-vector")      //object name
                (alloc_inst),
                segment
        );

      for(int i = 0; i < 100; ++i)  //Insert data in the vector
          elements->push_back(i);

      std::cout << elements->size() << std::endl;
        std::cout << elements->at(0) << std::endl;
        std::cout << elements->at(30) << std::endl;

      //Launch child process
      std::string s(argv[0]); s += " child ";
      if(0 != std::system(s.c_str()))
         return 1;

      std::cout << elements->size() << std::endl;
      std::cout << elements->at(0) << std::endl;
      std::cout << elements->at(30) << std::endl;

   }
   else{ //Child process
      //Open the managed segment
       managed_mapped_file segment(open_only, "./a_MySharedMemory.txt");
       const ShmemAllocator alloc_inst (segment.get_segment_manager());

       typedef boost::interprocess::managed_shared_ptr<MyVector, boost::interprocess::managed_mapped_file>::type map_pointer_type;

       map_pointer_type elements = boost::interprocess::make_managed_shared_ptr(
            segment.find_or_construct<MyVector>("some-vector")      //object name
            (alloc_inst),
            segment
    );

//       MyVector* elements = segment.find_or_construct<MyVector>("some-vector")      //object name
//                      (alloc_inst);

      //Use vector in reverse order
      std::sort(elements->rbegin(), elements->rend());

   }

   return 0;
}

在这种情况下,在子进程终止后,父进程中的向量大小为== 0。如果我使用原始指针(MyVector* elements = segment.find_or_construct...),那么可以在父进程中按预期使用该集合。

所以我仍然怀疑共享指针的行为

3 个答案:

答案 0 :(得分:2)

  • 问: 我是否以错误的方式初始化boost::interprocess::shared_ptr

你做得对。但是,您不需要共享指针中的段。只需确保该段超过任何进程间shared_ptrs(或者,对于共享内存段的任何引用)。

  • 问: 我完全错过了这个指针的语义 - &gt;它是否仅用于在一个进程内管理共享内存对象生命周期而不是跨进程?

没有

  • 问: 如何在进程间共享shared_ptr的{​​{1}}

文档:make_managed_shared_ptr

  

返回使用默认分配器和删除器构建的共享指针的实例,该指针是已在传递的托管段中分配的类型为T的指针

other page明确提及(强调我的):

  

由于必须在托管段中创建引用计数和shared_ptr所需的其他辅助数据,并且删除器必须从段中删除该对象,因此用户必须指定分配器对象和构造shared_ptr

的非空实例时的删除对象

答案 1 :(得分:2)

我设法解决了这个问题。问题与共享指针的制作方式有关

如果您调用boost::interprocess::make_managed_shared_ptr N次以创建共享内存中对象的共享指针,则会获得与共享内存中相同对象的本质上不同(完全不相关)的共享指针。我在Parent和Child进程中这样做,然后当Child进程死亡时,use count变为0并擦除了指向的对象(地图)。

解决方案是显式创建一个命名的共享指针。

typedef boost::interprocess::allocator<void, segment_manager_type>  void_allocator_type;
typedef boost::interprocess::deleter<map_type, segment_manager_type>  map_deleter_type;
typedef boost::interprocess::shared_ptr<map_type, void_allocator_type, map_deleter_type> map_pointer_type;

segment_manager_type* segment_manager = segment->get_segment_manager();
pair_allocator_type alloc_inst(segment_manager);

segment->construct<map_pointer_type>("elements ptr")(
            segment->construct<map_type>("elements")(std::less<IdClass>(), alloc_inst),      //object to own
            void_allocator_type(segment_manager),  //allocator
            map_deleter_type(segment_manager)         //deleter
            );

然后在Child进程中只获取此指针的副本

map_pointer_type elements = *segment->find<map_pointer_type>("elements ptr").first;

答案 2 :(得分:0)

我现在看到,如果我尝试在Child进程死后在共享内存中的父进程中创建任何对象,我会收到一个断言错误:

assertion "hdr->m_value_alignment == algn" failed: 
file "/usr/include/boost/interprocess/detail/segment_manager_helper.hpp", line 181, 
function: static boost::interprocess::detail::block_header* boost::interprocess::detail::block_header::block_header_from_value(const void*, size_t, size_t)

所以现在我怀疑这是我从父进程中生成子进程的方式。

  //Launch child process
  std::string s(argv[0]); s += " child";
  std::cout << "Child about to be born" <<  std::endl;

  if(0 != std::system(s.c_str())){
     std::cout << "(Parent): Child failed!" << std::endl;
     return 1;
  }