2013-02-05 46 views
3

死锁我看到一个死锁与std::mutex当互斥锁从DllMain()下面是一个最小的DLL测试用例,展现了我的问题。我的实际代码会执行互斥锁,因为它使用的成员函数在正常函数期间也可以在初始化之外使用。C++ 11 std ::从Visual Studio 2012死锁锁定从DllMain()

我认为问题是调度程序之间的死锁,如线程调用堆栈main()和调度程序产生的其他线程(可能)所见。实际执行main()之前似乎发生了死锁。

我将不胜感激关于如何修复/解决死锁的任何建议。

简单的DLL:

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; 
} 

在僵局的点有两个线程的过程:

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

这里是main()线程的调用堆栈:

[email protected]() Unknown 
    ntdll.dll!_TppWaitp[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 

第二个线程的调用栈很短:

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

编辑1:

WinDbg中证明了它是加载程序锁的问题:

PRIMARY_PROBLEM_CLASS: APPLICATION_HANG_HungIn_LoaderLock 
+5

也许[这](http://www.voyce.com/index.php/2009/12/03/dont-do-anything-in-dllmain-please/)可以帮助? –

+0

第二个线程调用堆栈看起来有些不完整,如果两者都以某种方式死锁,我会期望至少有一些函数访问那里的互斥量... – PlasmaHH

+0

@AndyProwl:如果你告诉我如何可靠地初始化DLL的状态,我会接受你的答案然后不使用'DllMain()'。:) – wilx

回答

1

看来,使用QueueUserAPC()排队初始化之前主(始终执行),但出来的可怕的装载机锁。这看起来像解决我的问题。

编辑1

一些测试后,它看来,如果我排队从DllMain()的APC,但如果我从一个类的静态全局实例的构造函数排队APC这是行不通的APC方法的工作原理。 IOW,使用APC并不能在所有可能的编译器和构建模式的组合中统一使用。

4

检查Best Practices for Creating DLLs文件:

你不应该从内部的DllMain执行下列任务:

  • 调用LoadLibrary或LoadLibraryEx(直接或间接)。这可能导致死锁或崩溃。
  • 与其他线程同步。这可能导致死锁。
+0

谁在与其他线程同步?我没有看到任何其他线程。 –

+0

故障点是互斥体,而不是其他线程。互斥量用于与其他线程同步。 –