我正在尝试通过Boost.Interprocess将std::vector<std::string>
转移到新的分叉进程中,以便子进程获得它的所有权并销毁它。检索和读取向量有效,但是销毁它时遇到访问冲突。我收集到分配器使用指向父代地址空间的指针启动了某种状态,而在子代的地址空间中没有意义。
我应该如何在父代中创建该向量并在子代中正确销毁?
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;
}
抛出异常:读取访问冲突。
_Pnext
是0x21FE21200B0
。发生
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()
答案 0 :(得分:0)
感谢Passer By促使我再次阅读Boost.Interprocess文档,我偶然发现了this example,这正是我想要做的。在确认它可以正常工作(确实可以)之后,我开始逐渐将其变形为自己程序的副本,然后发现了问题。
区别是选择std::vector
或boost::interprocess::vector
(也称为boost::container::vector
)。 std::vector
应该可以与自定义分配器配合使用,但是问题出在Microsoft的实现中:_Orphan_all
是发生访问冲突的功能,是Debug Iterators功能的一部分。该系统会跟踪哪个迭代器属于哪个容器,但是通过存储原始指针来做到这一点,当向量更改地址空间时,原始指针将变得陈旧,并且当向量试图在破坏时更新簿记数据时最终导致崩溃。
实际上,在发布模式(其中_ITERATOR_DEBUG_LEVEL == 0
和调试迭代器被停用的情况下进行编译)或使用Boost的vector
实现都可以正常工作。