2013-06-14 2 views
2

Раньше я задавал вопрос о перекрестном взаимодействии и поклялся, что прекращу использовать его, но, увы, я застрял, и мне действительно нужно, чтобы эта работа работала. Поэтому я все еще борюсь с этим.Поддерживает ли boost :: interprocess :: windows_shared_memory какую-либо специальную инициализацию при использовании внутри DLL?

У меня возникает странная авария при распределении, а затем сразу же уничтожается boost::interprocess::managed_windows_shared_memory::segment_manager, но это происходит только из проекта DLL, который я создаю. Я попытался воспроизвести его в автономной программе как способ сообщить об этом Boost, но он не воспроизводится вне моей собственной DLL.

Это также происходит, когда я создаю объект нормально и освобождаю его в более разумное время, но то, что я пытаюсь показать здесь, - это то, что Boost способен создать объект и что время не прошло и не было состояния изменился в куче, и все же Boost не может освободить этот объект без сбоев.

Это не происходит в автономном проекте образца (я построил один, чтобы посмотреть, будет ли он), но, тем не менее, никакой другой код, о котором я знаю, работает в проекте, где он сбой.

Что действительно странно, так это то, что он рушится из функции DLLMain, и это самое первое, что функция DLLMain выделяет, а затем уничтожает этот объект повышения C++. Что-то странно в этом повышающем объекте, что он создает много вещей (красное дерево), а затем даже не может очистить себя.

Код, приведенный ниже, является почти достаточным, чтобы воспроизвести проблему. Существует что-то не так с моей DLL, что делает в результате подталкивания объекты способны создавать себя, но они терпят крах при выключении:

// 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 еще не запущен другой код. Другие объекты могут быть созданы и освобождены, без проблем, только этот объект Boost не может быть создан или уничтожен в этой DLL.

B. Проект DLL скомпилирован с набором генерации кода как «Многопоточная библиотека отладки».

C. Деструктор для boost::interprocess::managed_windows_shared_memory::segment_manager всегда сбой в одном и том же месте, это не случайно. Это место mydll.dll!boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<....

D. Если я переключусь из разделяемой памяти Windows, в этом контексте DLL, другой вариант, просто вызванный shared_memory, он зависает вверх/блокировки в get_last_bootup_time при вызове WMI. Это функция из win32_api.hpp, которая вызывает вызов функции WMI окна и пытается прочитать свойство Win32_OperatingSystem класса LastBootUpTime.

E. Я начинаю думать, что DLL и Boost не любят друг друга, по странным странным причинам, возможно, с участием CoInitialize и темно-черной магией.

Как вы отлаживаете что-то такое безумное?

ответ

3

У DllMain есть довольно жесткие ограничения, основанные на том, что вы удерживаете Locker Lock при входе в эту функцию, а загрузчик библиотеки не будет правильно вычислять зависимости библиотек, если вы загружаете библиотеки в DllMain.

Действительно сложная часть всего этого заключается в том, что вы не можете удерживать Locker Lock прямо или косвенно. Например: вы не можете вызвать LoadLibrary, синхронизировать с другими потоками, вызвать CreateThread, управлять функциями управления памятью из CRT или вызвать что-либо из User32. Прочтите руководство по наилучшей практике DLL here (Microsoft) и посмотрите ссылки в конце документа.

Короткий ответ: не загружайте этот материал в DllMain.

+0

Oh Man. Я этого никогда не понимал. –

+1

Мне также нужно было настроить некоторые ресурсы в DLL (DLL-инъекции) и столкнулся с проблемой блокировки загрузчика в DllMain. То, что я сделал, было помещено все эти ресурсы/вещи, которые необходимо было загрузить в отдельный класс, который был ленивым загружен, когда это необходимо. –