C ++ 11 std :: mutex in Visual Studio 2012 deadlock quando bloccato da DllMain ()

Vedo un deadlock con std::mutex quando il mutex è bloccato da DllMain() Di seguito è riportato un caso di test DLL minimo che presenta il problema per me. Il mio codice effettivo esegue il blocco mutex perché utilizza funzioni membro utilizzabili anche al di fuori dell’inizializzazione durante la normale funzione.

Penso che il problema sia un deadlock tra lo scheduler visto nello stack di chiamate del thread main() e l’altro thread (probabilmente) generato dallo scheduler. Il deadlock sembra accadere prima che main() sia effettivamente eseguito.

Gradirei qualsiasi consiglio su come risolvere / risolvere il deadlock.

DLL semplice:

 static void testFunc() { std::mutex mtx; mtx.lock(); mtx.unlock(); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: testFunc (); break; case DLL_THREAD_ATTACH: testFunc (); break; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } 

Al punto del deadlock ci sono due thread nel processo:

 Not Flagged > 6408 0 Main Thread Main Thread msvcr110d.dll!Concurrency::details::SchedulerBase::SchedulerBase Normal Not Flagged 7600 0 Worker Thread ntdll.dl[email protected]() [email protected] Normal 

Ecco lo stack di chiamate del thread main() :

  [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown > msvcr110d.dll!Concurrency::details::SchedulerBase::SchedulerBase(const Concurrency::SchedulerPolicy & policy) Line 152 C++ msvcr110d.dll!Concurrency::details::ThreadScheduler::ThreadScheduler(const Concurrency::SchedulerPolicy & policy) Line 26 C++ msvcr110d.dll!Concurrency::details::ThreadScheduler::Create(const Concurrency::SchedulerPolicy & policy) Line 34 C++ msvcr110d.dll!Concurrency::details::SchedulerBase::CreateWithoutInitializing(const Concurrency::SchedulerPolicy & policy) Line 276 C++ msvcr110d.dll!Concurrency::details::SchedulerBase::GetDefaultScheduler() Line 650 C++ msvcr110d.dll!Concurrency::details::SchedulerBase::CreateContextFromDefaultScheduler() Line 567 C++ msvcr110d.dll!Concurrency::details::SchedulerBase::CurrentContext() Line 399 C++ msvcr110d.dll!Concurrency::details::LockQueueNode::LockQueueNode(unsigned int timeout) Line 616 C++ msvcr110d.dll!Concurrency::critical_section::lock() Line 1017 C++ msvcp110d.dll!mtx_do_lock(_Mtx_internal_imp_t * * mtx, const xtime * target) Line 65 C++ msvcp110d.dll!_Mtx_lock(_Mtx_internal_imp_t * * mtx) Line 144 C++ ConsoleApplicationDll.dll!std::_Mtx_lockX(_Mtx_internal_imp_t * * _Mtx) Line 68 C++ ConsoleApplicationDll.dll!std::_Mutex_base::lock() Line 43 C++ ConsoleApplicationDll.dll!testFunc() Line 16 C++ ConsoleApplicationDll.dll!DllMain(HINSTANCE__ * hModule, unsigned long ul_reason_for_call, void * lpReserved) Line 29 C++ ConsoleApplicationDll.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 508 C ConsoleApplicationDll.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 472 C [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown 

Lo stack di chiamate del secondo thread è breve:

 > [email protected]() Unknown [email protected]() Unknown [email protected]() Unknown 

MODIFICA 1:

WinDbg conferma che si tratta di un problema di blocco del caricatore:

 PRIMARY_PROBLEM_CLASS: APPLICATION_HANG_HungIn_LoaderLock 

Controllare il documento Best Practices per la creazione di DLL :

Non eseguire mai le seguenti attività da DllMain:

  • Chiama LoadLibrary o LoadLibraryEx (direttamente o indirettamente). Ciò può causare un deadlock o un arresto anomalo.
  • Sincronizza con altri thread. Ciò può causare un deadlock.

Sembra che l’utilizzo di QueueUserAPC() per l’inizializzazione delle code sia sempre eseguito prima di main () ma fuori dal blocco del loader temuto. Questa sembra una soluzione al mio problema.

MODIFICA 1

Dopo alcuni test sembra che il metodo APC funzioni se DllMain() l’APC da DllMain() ma non funziona se accodo l’APC da un ctor di un’istanza globale statica di una class. IOW, l’utilizzo dell’APC non è uniformsmente utilizzabile per tutte le possibili combinazioni di compilatori e modalità di compilazione per me.