【问题标题】:Boost.Interprocess crashes when destroy an object in a mpi processBoost.Interprocess 在 mpi 进程中销毁对象时崩溃
【发布时间】:2022-08-15 00:49:05
【问题描述】:

我在父进程中创建了一个 shm,然后通过system 启动 mpiexec。

在这些 mpi 引导的进程中,打开了 shm。它可以通过find<Type>(\"name\") 找到对象,但是当它尝试destroy<Type>(name) 时,出现错误。

void Foo::DumpInitialData()
{
    using namespace boost::interprocess;
    shared_memory_object::remove(\"MySHM\");
    typedef allocator<char, managed_shared_memory::segment_manager>
        ShmCharAllocator;
    typedef std::basic_string<char, std::char_traits<char>, ShmCharAllocator>
        ShmStr;

    string try_str;
    {
        ostringstream try_ss;
        Foo split(*this, ...);
        BinarySerialization ser(split);
        ser.Dump(try_ss);
        try_str = try_ss.str();
    }
    size_t try_size = sizeof(ShmStr) + 512
        + (try_str.capacity() + 1) * sizeof(char);

    managed_shared_memory segment(create_only, \"MySHM\", 
        try_size * (split_size + 1));
    ShmCharAllocator alloc_chars(segment.get_segment_manager());
    segment.construct<ShmStr>(
            (\"Mpi\" + to_string(0)).c_str(
    ))(try_str, alloc_chars); 

    try {
        for (int i = 1; i < split_size; ++i) {
            stringstream ss;
            Foo split(*this, ...);
            BinarySerialization ser(split);
            ser.Dump(ss);

            segment.construct<ShmStr>((\"Mpi\" + to_string(i)).c_str())
                (ss.str(), alloc_chars);
        }
    } catch (interprocess_exception &e) {
        throw ...Exception(
            \"No enough shared memeroy to passing split data.\"
        );
    }
}

...

void Foo::PumpMpiInitialData(int i)
{
    auto& world = mpi->world();
    vector<string> send(world.size());
    decltype(send)::value_type recv;
    if (i == 0) {
        using namespace boost::interprocess;
        typedef allocator<char, managed_shared_memory::segment_manager>
            ShmCharAllocator;
        typedef std::basic_string<
            char, std::char_traits<char>, ShmCharAllocator
        > ShmStr;
        {
            managed_shared_memory segment(
                open_only, \"MySHM\"
            );

            for_each(send | ba::indexed(), [&](const auto& s_it) {
                auto name = \"Mpi\" + to_string(s_it.index());
                const char* c_name = name.c_str();
                ShmStr* data = segment.find<ShmStr>(c_name).first;
                s_it.value() = string(*data);
                // This will failed.
                bool succ = segment.destroy<ShmStr>(c_name);
            });
        }
        shared_memory_object::remove(\"MySHM\");
    }
    bm::scatter(world, send, recv, 0);

    BinarySerialization ser(*this);
    istringstream ss(recv);
    ser.Pump(ss);
}

以下调用堆栈发生错误:

>   ....exe!std::_Container_base12::_Orphan_all_unlocked_v3() Line 1243 C++
    ....exe!std::_Container_base12::_Orphan_all_locked_v3() Line 1098   C++
    ....exe!std::_Container_base12::_Orphan_all() Line 1260 C++
    ....exe!std::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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>::_Tidy_deallocate() Line 4618 C++
    ....exe!std::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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>::~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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>() Line 3005    C++
    ....exe!std::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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>::`scalar deleting destructor\'(unsigned int)   C++
    ....exe!boost::interprocess::ipcdetail::placement_destroy<std::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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>>::destroy_n(void * mem, unsigned __int64 num, unsigned __int64 & destroyed) Line 61 C++
    ....exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::priv_generic_named_destroy<char>(const char * name, boost::interprocess::iset_index<boost::interprocess::ipcdetail::index_config<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>>> & index, boost::interprocess::ipcdetail::in_place_interface & table, boost::interprocess::ipcdetail::bool_<1> is_intrusive_index) Line 992    C++
    ....exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::destroy<std::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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>>(boost::interprocess::ipcdetail::char_ptr_holder<char> name) Line 553  C++
    ....exe!boost::interprocess::ipcdetail::basic_managed_memory_impl<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index,8>::destroy<std::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,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>>(const char * name) Line 568    C++
    ....exe!<lambda_da719d1c74e37fe397eecaa291110c18>::operator()<boost::range::index_value<std::string &,__int64>>(const boost::range::index_value<std::string &,__int64> & s_it) Line 222 C++
...

没有 mpi 的类似情况可以正常工作,如下所示。

int main(int argc, char *argv[])
{
   using namespace boost::interprocess;
   typedef allocator<char, managed_shared_memory::segment_manager>
        ShmCharAllocator;
   typedef std::basic_string<char, std::char_traits<char>, ShmCharAllocator>
        ShmStr;

   if(argc == 1){  //Parent process
      //Remove shared memory on construction and destruction
      struct shm_remove
      {
         shm_remove() { shared_memory_object::remove(\"MySharedMemory\"); }
         ~shm_remove(){ shared_memory_object::remove(\"MySharedMemory\"); }
      } remover;

      {

      //Construct managed shared memory
      managed_shared_memory segment(create_only, \"MySharedMemory\", 65536);

      const ShmCharAllocator alloc_inst(segment.get_segment_manager());
      //Create an object of MyType initialized to {0.0, 0}
      segment.construct<ShmStr>(\"MyType0\")(string(\"abc\"), alloc_inst);

      }

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


   } else {
       {
           using namespace std::chrono_literals;
           std::this_thread::sleep_for(10s);
       }


      //Open managed shared memory
      managed_shared_memory segment(open_only, \"MySharedMemory\");

      const string str = \"MyType0\";
      auto* res = segment.find<ShmStr>(str.c_str()).first;
      string a = string(*res);
      //Length should be 1
      //if(res.second != 1)
      //    return 1;

      segment.destroy<ShmStr>(str.c_str());
   }
   return 0;
}

    标签: windows boost mpi interprocess


    【解决方案1】:

    很难看出所有神奇数字的含义。你正在处理sizeof(ShmStr) 这是一个很大的危险信号,因为它不是一个微不足道的类型。

    您使用托管段也很“奇怪”,但尝试手动进行所有内存管理。为什么不在段内存储一个实际的队列?

    请注意,您似乎是在使用命名分配来模拟数组支持,但数组支持是built-in to segment managers

    最后,我不使用 MPI,但我记得它has builtin support for boost serialization 的方式,这意味着您不需要将所有数据复制到字符串流中,然后再复制到字符串中,进入共享内存对象等。这不是最佳的。

    接下来,您正在使用来自多个进程(MPI 进程)的共享内存段,但您没有锁定任何内容。例如,destroy&lt;&gt; 将修改其他进程仍在读取的共享对象。此外,如果您要从所有进程中销毁,那么您将多次销毁事物(Undefined Behaviour)。

    最后,如果你没问题

        bip::shared_memory_object::remove("MySHM");
    

    最后,不要费心破坏单个拆分元素吗?

    【讨论】:

      猜你喜欢
      • 2020-04-10
      • 2011-03-03
      • 2019-04-08
      • 1970-01-01
      • 1970-01-01
      • 2012-04-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多