当从DLL内部使用时,boost :: interprocess :: windows_shared_memory是否需要任何特殊的初始化?

时间:2013-06-14 03:23:45

标签: c++ visual-c++ boost visual-c++-2008 boost-interprocess

之前我问过一个提升 - 进程间问题,发誓我会停止使用它,但唉,我被卡住了,我真的需要这个东西才能工作。所以我还在和它斗争。

我在分配然后立即销毁boost::interprocess::managed_windows_shared_memory::segment_manager时遇到了一个奇怪的崩溃,但它只发生在我正在构建的Windows DLL项目中。我尝试在独立程序中重现它作为向Boost报告它的方法,但它不会在我自己的DLL之外重现。

当我正常创建对象并在更加理智的时候释放它时也会发生这种情况,但我想在这里展示的是Boost能够创建一个对象,并且没有时间过去且没有状态在堆中更改,但Boost无法在不崩溃的情况下释放此对象。

这不会发生在一个独立的示例项目中(我构建了一个,只是为了查看它是否会发生),但是,我所知道的其他任何代码都没有在崩溃的项目中运行。

真正奇怪的是它从DLLMain函数崩溃了,它是DLLMain函数中首先分配然后销毁这个C ++ boost对象的东西。这个提升对象有点奇怪,它创造了很多东西(一个红黑树),然后甚至无法自我清理。

以下代码几乎但不足以重现该问题。我的DLL出了问题,导致生成的Boost对象能够自己创建,但是在关闭时会崩溃:

// BoostDllMain.cpp :
//
//  Attempt to demonstrate an insane situation in my code, where
//  boost::interprocess::managed_windows_shared_memory::segment_manager 
//  can be created, but freeing it causes access violations. The context
//  for object creation and destruction is DLL load and unload time.



#include "stdafx.h"

#include <objbase.h>
#include <windows.h>



#ifdef PERSISTENT_SHARED_MEM
#include <boost/interprocess/managed_shared_memory.hpp>
#else
#include <boost/interprocess/managed_windows_shared_memory.hpp>
#endif

#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>

#define SHARED_AREA_SIZE (1024*1024*8)  // 8 megabytes of shared memory should be enough to store more than 60K data points. 
                                    // In testing using current structure sizes, allocation Failed at the 61678th 
                                    // data point item when set to this value.



#ifdef PERSISTENT_SHARED_MEM
typedef boost::interprocess::managed_shared_memory                  mgr;
typedef boost::interprocess::managed_shared_memory::segment_manager seg;
#else
typedef boost::interprocess::managed_windows_shared_memory                  mgr;
typedef boost::interprocess::managed_windows_shared_memory::segment_manager seg;
#endif

using namespace boost::interprocess;

mgr *       segment1;
mgr *       segment2;

void Init(void) {

// Tweak C Runtime Debug Heap Flags.
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
tmpFlag |= _CRTDBG_CHECK_CRT_DF;
_CrtSetDbgFlag( tmpFlag );  

      segment1 = new mgr(   open_or_create
                           , "ED3_MEMORY" // This is a global memory area name

                           , SHARED_AREA_SIZE );    
      segment2 = new mgr(   open_or_create
                           , "ED3_MEMORY" // This is a global memory area name

                           , SHARED_AREA_SIZE );  
}

void Cleanup(void) {

     delete segment1;
     segment1 = NULL;


     delete segment2;
     segment2 = NULL;


}

//
extern "C"
BOOL WINAPI DllMain(IN HANDLE hInstance, IN DWORD dwReason, IN VOID *pReserved )
{



    switch ( dwReason )
    {
    case DLL_PROCESS_ATTACH:

        Init();

        break;

    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;

    case DLL_PROCESS_DETACH:

        Cleanup();


        break;

    default:
        break;
    }

    return(1);
}

简而言之,对于managed_windows_shared_memory,无论你创建什么对象,甚至不能立即彻底破坏(没有访问冲突),这就是我试图在上面展示的,我在DLL中创建对象的地方加载,并在DLL卸载时将其销毁。

这是一个堆栈追溯。如果你能理解它,你可能是一个C ++编译器,而不是一个人,但不管怎样,它在这里:

>   mydll.dll!boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0>::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0>(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & ptr={...})  Line 272 + 0xf bytes   C++
    mydll.dll!boost::intrusive::compact_rbtree_node_traits_impl<boost::interprocess::offset_ptr<void,int,unsigned int,0> >::get_left(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & n={...})  Line 142 + 0x1d bytes   C++
    mydll.dll!boost::intrusive::detail::tree_algorithms<boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1> >::dispose_subtree<boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > >(boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> x={...}, boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > disposer={...})  Line 1298 + 0xd bytes  C++
    mydll.dll!boost::intrusive::detail::tree_algorithms<boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1> >::clear_and_dispose<boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > >(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & header={...}, boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > disposer={...})  Line 577 + 0x15 bytes   C++
    mydll.dll!boost::intrusive::rbtree_algorithms<boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1> >::clear_and_dispose<boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > >(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & header={...}, boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > disposer={...})  Line 451 + 0x16 bytes C++
    mydll.dll!boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::clear_and_dispose<boost::intrusive::detail::null_disposer>(boost::intrusive::detail::null_disposer disposer={...})  Line 1006 + 0x26 bytes C++
    mydll.dll!boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::clear()  Line 987  C++
    mydll.dll!boost::intrusive::detail::clear_on_destructor_base<boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > >::~clear_on_destructor_base<boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > >()  Line 27  C++
    mydll.dll!boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::~rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >()  Line 284 + 0x14 bytes  C++
    mydll.dll!boost::intrusive::set_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::~set_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >()  Line 139 + 0x14 bytes    C++
    mydll.dll!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> > >::~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> > >()  + 0x14 bytes    C++
    mydll.dll!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>::header_t::~header_t()  + 0x3d bytes    C++
    mydll.dll!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>::~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>()  + 0x3d bytes  C++
    mydll.dll!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>::`scalar deleting destructor'()  + 0x14 bytes   C++

总之我有

一个。排除了我编写的代码中的堆损坏,因为还没有其他代码在此DLL的上下文中运行。可以创建和释放其他对象,没问题,只能在此DLL中创建或销毁此Boost对象。

B中。正在编译DLL项目,代码生成设置为“多线程调试DLL”。

℃。 boost::interprocess::managed_windows_shared_memory::segment_manager的析构函数总是在同一个地方崩溃,它不是随机的。那个地方是mydll.dll!boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<...

d。如果我从这个DLL上下文中的Windows共享内存切换到另一个选项(仅称为shared_memory),它会在WMI调用中冻结get_last_bootup_time中的/死锁。这是win32_api.hpp中的一个函数,它执行Window WMI函数调用并尝试读取类Win32_OperatingSystem属性LastBootUpTime

电子。我开始认为DLL和Boost彼此不喜欢,因为奇怪的奇怪原因,可能涉及CoInitialize和深黑魔法。

你如何调试这个疯狂的东西?

1 个答案:

答案 0 :(得分:3)

DllMain有一些非常严格的限制,因为你在进入这个函数时持有Loader Lock,如果在DllMain中加载库,库加载器将无法正确计算库依赖性。

关于所有这一切的真正棘手的部分是你不能直接或间接地持有Loader Lock。例如:您不能调用LoadLibrary,与其他线程同步,调用CreateThread,从CRT调用内存管理函数,或从User32调用任何内容。请阅读DLL最佳实践指南here (Microsoft),并查看文档末尾的参考资料。

简短回答:不要在DllMain中加载这些东西。