c++ - 在另一个进程中销毁共享的 std::vector

标签 c++ c++17 boost-interprocess

我正在尝试传输 std::vector<std::string>通过 Boost.Interprocess 到一个新的 fork 进程,这样子进程就可以取得它的所有权并销毁它。检索和读取 vector 有效,但是我在销毁它时遇到访问冲突。我收集到分配器开始了一些带有指针的状态,这些指针指向父地址空间并且在子地址空间中毫无意义。

我应该如何在父级中创建该 vector 并在子级中正确销毁?

父进程代码:

namespace ip = boost::interprocess;

template <class T>
using ip_allocator = ip::allocator<T, ip::managed_shared_memory::segment_manager>;

template <class T>
using ip_vector = std::vector<T, ip_allocator<T>>;

int CALLBACK WinMain(
    _In_ HINSTANCE,
    _In_ HINSTANCE,
    _In_ LPSTR,
    _In_ int
) {
    ip::shared_memory_object::remove("MyTestShm");
    ip::managed_shared_memory mshm{ ip::open_or_create, "MyTestShm", 1024 * 1024 };

    ip_allocator<int> intAlloc{ mshm.get_segment_manager() };

    mshm.construct<ip_vector<int>>("ForkData")(
        ip_vector<int>{ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, intAlloc}
    );

    boost::process::spawn(L"Executor.exe", L"ForkData");
}

子进程(Executor.exe)代码:

int wmain(int argc, wchar_t **argv) try {
    namespace ip = boost::interprocess;

    // Kludge to attach the debugger and force continuation
    bool volatile coin = true;
    while (coin)
        ::Sleep(1000);

    ip::managed_shared_memory mshm{ ip::open_only, "MyTestShm" };
    auto const * const fd = mshm.find<ip_vector<int>>("ForkData").first;

    if(!fd)
        return 1;

    for (int i : *fd)
        std::cout << i << ' ';
    std::cout << '\n';

    mshm.destroy_ptr(fd); // Crashing line
}
catch (std::exception const &exc) {
    std::cerr
        << "Unhandled " << boost::typeindex::type_id_runtime(exc).pretty_name() << ":\n"
        << exc.what() << '\n';
    return 1;
}

错误和调用栈:

Exception thrown: read access violation. _Pnext was 0x21FE21200B0. occurred

Executor.exe!std::_Container_base12::_Orphan_all() Line 221
Executor.exe!std::_Vector_alloc<std::_Vec_base_types<int,boost::interprocess::allocator<int,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> > > >::_Orphan_all() Line 536
Executor.exe!std::vector<int,boost::interprocess::allocator<int,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() Line 1913
Executor.exe!std::vector<int,boost::interprocess::allocator<int,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> > >::~vector<int,boost::interprocess::allocator<int,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 894
Executor.exe!std::vector<int,boost::interprocess::allocator<int,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)   Executor.exe!boost::interprocess::ipcdetail::placement_destroy<std::vector<int,boost::interprocess::allocator<int,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
Executor.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 976
Executor.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>(boost::interprocess::ipcdetail::block_header<unsigned __int64> * block_header, 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_<0> is_node_index) Line 929
Executor.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_destroy_ptr(const void * ptr, boost::interprocess::ipcdetail::in_place_interface & dtor) Line 777
Executor.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_ptr<std::vector<int,boost::interprocess::allocator<int,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 std::vector<int,boost::interprocess::allocator<int,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> > > * p) Line 550
Executor.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_ptr<std::vector<int,boost::interprocess::allocator<int,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 std::vector<int,boost::interprocess::allocator<int,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> > > * ptr) Line 608
Executor.exe!wmain(int argc, wchar_t * * argv) Line 31
Executor.exe!invoke_main() Line 91
Executor.exe!__scrt_common_main_seh() Line 288
Executor.exe!__scrt_common_main() Line 331
Executor.exe!wmainCRTStartup() Line 17
kernel32.dll!BaseThreadInitThunk()
ntdll.dll!RtlUserThreadStart()

最佳答案

感谢Passer By谁提示我再次阅读 Boost.Interprocess 文档,我偶然发现了 this example ,幸运的是,这正是我想要做的。在确认它对我有效(确实如此)后,我开始逐渐将其变形为我自己程序的拷贝,并发现了问题。

不同之处在于选择 std::vectorboost::interprocess::vector(也称为 boost::container::vector )。 std::vector 应该可以与自定义分配器一起正常工作,但问题出在 Microsoft 的实现中:_Orphan_all,发生访问冲突的函数是Debug Iterators功能。该系统跟踪哪个迭代器属于哪个容器,但通过存储原始指针来实现,随着 vector 更改地址空间,原始指针变得陈旧,并最终在 vector 试图在销毁时更新簿记数据时导致崩溃。

事实上,在 Release模式下编译(其中 _ITERATOR_DEBUG_LEVEL == 0 和调试迭代​​器被停用)或使用 Boost 的 vector 实现都可以完美地工作。

关于c++ - 在另一个进程中销毁共享的 std::vector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53211323/

相关文章:

C++ 类前向声明​​的缺点?

c++ - 存储最后 n 秒内获取的数据点的最佳数据结构是什么

c++ - 如何解决 std::get<>() 缺乏并发规范的问题

c++ - 使用优化标志编译时线程不启动

c++ - 进程间通信 : Shared memory vs thread object access

c++ - 创建静态库时,是否需要包含每个依赖项?

c++ - 如何使用 Win32 解码 JPEG?

c++ - 内联变量的多次销毁

c++ - boost::interprocess 准备好迎接黄金时段了吗?

c++ - 使用 boost::interprocess::file_lock 创建一个锁定文件