C++ 如何调试或修复涉及boost::进程间托管共享内存的无休止循环和堆损坏问题?
我有下面的“第一次机会异常”消息,它来自我编写的DLL,该DLL在我没有编写的可执行文件中运行。也就是说,DLL是一个插件。首次触发此异常时,打开共享内存映射文件的尝试失败。如果我忽略第一次出现的异常而只是运行,应用程序最终会冻结或崩溃C++ 如何调试或修复涉及boost::进程间托管共享内存的无休止循环和堆损坏问题?,c++,boost,visual-c++-2008,boost-interprocess,C++,Boost,Visual C++ 2008,Boost Interprocess,我有下面的“第一次机会异常”消息,它来自我编写的DLL,该DLL在我没有编写的可执行文件中运行。也就是说,DLL是一个插件。首次触发此异常时,打开共享内存映射文件的尝试失败。如果我忽略第一次出现的异常而只是运行,应用程序最终会冻结或崩溃 First-chance exception at 0x76a7c41f in notmyexe.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memor
First-chance exception at 0x76a7c41f in notmyexe.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memory location 0x002bc644..
几个小时后,它似乎是由一个代码块引起的,该代码块不断循环,直到预期的异常条件清除为止。事实证明,如果它从未清除,那么最终,这个异常会变成另一个低级异常情况和/或变成堆损坏。所有这些都只是为了使用Boost::interprocess打开共享内存区域
<> P>第一个复杂的事情是,在Visual C++ 2008项目中,第一个<代码> Boo::ItPoalExtExabutyExabue/Cuth>第一个机会异常不会被抛出,并被识别为它来自的位置,因为VisualC++ 2008编译器无法找到复杂的Boost味道模板代码。然而,通过单步遍历汇编语言视图,我发现了代码
我自己的代码中最顶层的一行开始出现问题:
segment = new managed_shared_memory( open_or_create
, MEMORY_AREA_NAME
, SHARED_AREA_SIZE );
上述managed_shared_memory
类来自interprocess_fwd.hpp,是boost共享内存API/头的标准部分。因为它是基于模板的,所以扩展到了2KCHARS长C++的Boost模板表达式,它由链接器和调试器截断在不同长度。Visual C++ 2008没有更多的源代码调试能力,似乎在这些限制发挥作用时。
例如,当它爆炸时,我得到以下调用堆栈:
KernelBase.dll!76a7c41f()
[Frames below may be incorrect and/or missing, no symbols loaded for KernelBase.dll]
KernelBase.dll!76a7c41f()
> msvcr90d.dll!_malloc_dbg(unsigned int nSize=2290875461, int nBlockUse=264, const char * szFileName=0x01fcb983, int nLine=1962999808) Line 160 + 0x1b bytes C++
8bfc4d89()
上面的堆栈转储中没有实际的最终用户编写的源函数
我应该如何调试它?第二,在Visual C++ 2008中有一些已知的Boost进程间的问题吗?第三,下面的boost代码在做什么?为什么它必须无休止地循环
boost::interprocess::basic_managed_shared_memory<char,
boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,
boost::interprocess::iset_index>::basic_managed_shared_memory<char,boo...
无论如何,孩子们,不要试图在家里调试这个,下面是发生的情况:
<>最后,用我忍者般的能力单步通过几百万条汇编语言,我打败了Visual C++ 2008的调试程序,并找到了代码。p>
事实上,这就是爆炸的原因:创建设备(dev.
)
这里有一些背景:
托管\u打开\u或\u创建\u impl.h行351
else if(type == DoOpenOrCreate){
//This loop is very ugly, but brute force is sometimes better
//than diplomacy. If someone knows how to open or create a
//file and know if we have really created it or just open it
//drop me a e-mail!
bool completed = false;
while(!completed){
try{
create_device<FileBased>(dev, id, size, perm, file_like_t()); // <-- KABOOM!
created = true;
completed = true;
}
catch(interprocess_exception &ex){
if(ex.get_error_code() != already_exists_error){
throw;
}
else{
try{
DeviceAbstraction tmp(open_only, id, read_write);
dev.swap(tmp);
created = false;
completed = true;
}
catch(interprocess_exception &e){
if(e.get_error_code() != not_found_error){
throw;
}
}
catch(...){
throw;
}
}
}
catch(...){
throw;
}
thread_yield();
}
}
else if(type==DoOpenOrCreate){
//这个循环非常丑陋,但暴力有时更好
//而不是外交。如果有人知道如何打开或创建
//文件,并知道我们是否真的创建了它或只是打开它
//给我发封电子邮件!
bool completed=false;
而(!已完成){
试一试{
创建设备(dev、id、size、perm、file_like_t());//Boost充满了令人惊异和可怕的东西
在Windows上,一个简单的解决方法是切换到托管的\u Windows\u共享的\u内存
而不是托管的\u共享的\u内存
,您可以解决各种严重的崩溃/挂起问题,而一种崩溃/挂起问题似乎是由Windows文件系统行为和unix文件系统行为之间的差异引起的iour,特别是,在Windows上使用boost和托管共享内存
,可能会与Windows文件系统锁定限制发生冲突。我被告知boost 1.53已经完成了处理这一问题的工作,但我使用的是boost 1.53,我仍然有这个问题
使用Windows上的常规托管共享内存
,您可以在任何客户端或服务器应用程序的生命周期之外获得持久性。这在某些人的情况下可能是可取的,因此解决方案对这些人来说不是一个真正的解决方案
然而,在我的例子中,我并不真的需要它,尽管我认为它会很方便,但结果证明它比它的价值更痛苦,至少在Windows上当前的Boost实现中是如此
我还想指出,删除共享内存文件似乎是引发上述问题的竞争条件的根本原因。围绕创建、检查和删除文件的适当同步似乎对系统的实际实现至关重要,尤其是此外,如果您让您的主机(服务器)在某些客户端仍在使用共享内存文件时删除该文件,这似乎是一个灾难性的问题。需要重新启动以清除由此产生的锁定+NTFS文件系统混乱
如果我找到一个真正的解决方案,我会发布它,但是上面的信息比我在任何地方都能找到的更多。请谨记<代码> MauleDySyddLoad ,并考虑使用<代码> MaundsWielsSySyddLoad < /代码>,忘记尝试创建“持久共享内存”。想法有效。相反,只使用非持久性窗口
管理的\u窗口\u共享的\u内存
要解决这个问题,在我的应用程序中保留managed\u shared\u memory
类可能意味着将对managed\u shared\u memory
对象的所有访问包装在另一个级别的进程间同步原语中,甚至使用原始Win32 API互斥对象。Boost可以做一些等效的事情,但可能会引入更偶然的复杂性
(旁白:我是这里唯一一个认为模板在一般使用中,尤其是在Boost中,这些天所有东西都做得太过分的人吗?)
更新2:我找到了另一种冻结托管共享内存的方法,这反过来会冻结您使用它的任何应用程序。我没想到用Boost创建死锁会这么容易,但这很容易。互斥锁c
else if(type == DoOpenOrCreate){
//This loop is very ugly, but brute force is sometimes better
//than diplomacy. If someone knows how to open or create a
//file and know if we have really created it or just open it
//drop me a e-mail!
bool completed = false;
while(!completed){
try{
create_device<FileBased>(dev, id, size, perm, file_like_t()); // <-- KABOOM!
created = true;
completed = true;
}
catch(interprocess_exception &ex){
if(ex.get_error_code() != already_exists_error){
throw;
}
else{
try{
DeviceAbstraction tmp(open_only, id, read_write);
dev.swap(tmp);
created = false;
completed = true;
}
catch(interprocess_exception &e){
if(e.get_error_code() != not_found_error){
throw;
}
}
catch(...){
throw;
}
}
}
catch(...){
throw;
}
thread_yield();
}
}
boost::interprocess::managed_shared_memory * segment;
std::pair<MyType*, std::size_t> f = segment->find<MyType>(name);
> myapp.exe!boost::interprocess::winapi::sched_yield() Line 998 C++
myapp.exe!boost::interprocess::ipcdetail::thread_yield() Line 60 + 0xe bytes C++
myapp.exe!boost::interprocess::ipcdetail::spin_mutex::lock() Line 71 C++
myapp.exe!boost::interprocess::ipcdetail::spin_recursive_mutex::lock() Line 91 C++
myapp.exe!boost::interprocess::interprocess_recursive_mutex::lock() Line 161 C++
myapp.exe!boost::interprocess::scoped_lock<boost::interprocess::interprocess_recursive_mutex>::lock() Line 280 C++
myapp.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::priv_get_lock(bool use_lock=true) Line 1340 C++
myapp.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::priv_generic_find<char>(const char * name=0x00394290, boost::interprocess::iset_index<boost::interprocess::ipcdetail::index_config<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0> > > & index={...}, boost::interprocess::ipcdetail::in_place_interface & table={...}, unsigned int & length=1343657312, boost::interprocess::ipcdetail::bool_<1> is_intrusive={...}, bool use_lock=true) Line 854 + 0x11 bytes C++
myapp.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::priv_find_impl<boost::container::map<AreaKeyType,DATA_AREA_DESC,std::less<AreaKeyType>,boost::interprocess::allocator<std::pair<AreaKeyType const ,DATA_AREA_DESC>,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index> > > >(const char * name=0x00394290, bool lock=true) Line 728 + 0x25 bytes C++
myapp.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::find<boost::container::map<AreaKeyType,DATA_AREA_DESC,std::less<AreaKeyType>,boost::interprocess::allocator<std::pair<AreaKeyType const ,DATA_AREA_DESC>,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index> > > >(const char * name=0x00394290) Line 423 + 0x1e bytes C++
myapp.exe!boost::interprocess::ipcdetail::basic_managed_memory_impl<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index,8>::find<boost::container::map<AreaKeyType,DATA_AREA_DESC,std::less<AreaKeyType>,boost::interprocess::allocator<std::pair<AreaKeyType const ,DATA_AREA_DESC>,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index> > > >(boost::interprocess::ipcdetail::char_ptr_holder<char> name={...}) Line 346 + 0x23 bytes C++
myapp.exe!boost::interprocess::basic_managed_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::find<boost::container::map<AreaKeyType,DATA_AREA_DESC,std::less<AreaKeyType>,boost::interprocess::allocator<std::pair<AreaKeyType const ,DATA_AREA_DESC>,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index> > > >(boost::interprocess::ipcdetail::char_ptr_holder<char> name={...}) Line 208 + 0x10 bytes C++
myapp.exe!CCommonMemory::AllocateOrFindAreaMap(const char * name=0x00394290) Line 128 C++
inline bool shared_memory_object::priv_open_or_create
(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
{
m_filename = filename;
std::string shmfile;
std::string root_tmp_name;
//Set accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
switch(type){
case ipcdetail::DoOpen:
ipcdetail::get_tmp_base_dir(root_tmp_name);
shmfile = root_tmp_name;
shmfile += "/";
shmfile += filename;
m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
break;
case ipcdetail::DoCreate:
ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, shmfile);
m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
break;
case ipcdetail::DoOpenOrCreate:
ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, shmfile);
m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == ipcdetail::invalid_file()){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
m_mode = mode;
return true;
}