C ++ 11 std :: mutex在Visual Studio 2012死锁时从DllMain() [英] C++11 std::mutex in Visual Studio 2012 deadlock when locked from DllMain()

查看:1239
本文介绍了C ++ 11 std :: mutex在Visual Studio 2012死锁时从DllMain()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当互斥锁从 DllMain()锁定时,我看到有 std :: mutex 一个最小的DLL测试用例,显示我的问题。我的实际代码做mutex锁定,因为它使用成员函数,在正常的函数期间也可以在初始化之外使用。



我认为问题是调度器之间的死锁在调用堆栈 main()线程和其他线程(可能)由调度器产生。死锁似乎发生在 main()之前。



修复/解决死锁。



简单的DLL:

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

在死锁的时候,有两个线程: p>

 未标记> 6408 0主线程主线程msvcr110d.dll!并发:: details :: SchedulerBase :: SchedulerBase正常
未标记7600 0工作线程ntdll.dll!_TppWaiterpThread@4()ntdll.dll!_NtDelayExecution@8正常

这里是 main()

  ntdll.dll!_NtWaitForKeyedEvent@16()未知
ntdll.dll!_TppWaitpSet@16 b $ b ntdll.dll!_TppSetWaitInterrupt@12()未知
ntdll.dll!_RtlRegisterWait@24()未知
kernel32.dll!_RegisterWaitForSingleObject@24()未知
> msvcr110d.dll!Concurrency :: details :: SchedulerBase :: SchedulerBase(const Concurrency :: SchedulerPolicy& policy)行152 C ++
msvcr110d.dll!并发:: details :: ThreadScheduler :: ThreadScheduler(const Concurrency :: SchedulerPolicy& policy)第26行C ++
msvcr110d.dll!Concurrency :: details :: ThreadScheduler :: Create(const Concurrency :: SchedulerPolicy& policy)第34行C ++
msvcr110d.dll!详细信息:: SchedulerBase :: CreateWithoutInitializing(const Concurrency :: SchedulerPolicy& policy)行276 C ++
msvcr110d.dll!并发:: details :: SchedulerBase :: GetDefaultScheduler()行650 C ++
msvcr110d.dll !并发::细节:: SchedulerBase :: CreateContextFromDefaultScheduler()行567 C ++
msvcr110d.dll!并发::细节:: SchedulerBase :: CurrentContext()行399 C ++
msvcr110d.dll!并发::详细信息:: LockQueueNode :: LockQueueNode(unsigned int timeout)行616 C ++
msvcr110d.dll!Concurrency :: critical_section :: lock()行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)行144 C ++
ConsoleApplicationDll.dll!std :: _ Mtx_lockX(_Mtx_internal_imp_t * * _Mtx)行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)472 C
ntdll.dll!_LdrpCallInitRoutine@16()未知
ntdll.dll!_LdrpRunInitializeRoutines@4()未知
ntdll.dll!_LdrpInitializeProcess@8()未知
ntdll.dll!__ LdrpInitialize @ 8()未知
ntdll.dll!_LdrInitializeThunk@8()未知

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

 > ntdll.dll._NtDelayExecution@8()未知
ntdll.dll!__ LdrpInitialize @ 8()未知
ntdll.dll!_LdrInitializeThunk@8()未知

编辑1:



WinDbg确认它是加载器锁定问题:

  PRIMARY_PROBLEM_CLASS:APPLICATION_HANG_HungIn_LoaderLock 


似乎使用 QueueUserAPC()到队列初始化总是在main()之前执行,可怕的加载锁。这看起来像是我的问题的解决方案。



编辑1



测试看起来APC方法工作,如果我从 DllMain()队列APC,但它不工作,如果我从一个静态全局实例的ctor排队APC类。 IOW,使用APC不是统一可用的编译器的所有可能的组合和构建模式为我。


I am seeing a deadlock with std::mutex when the mutex is locked from DllMain() Below is a minimal DLL test case that exhibits the problem for me. My actual code does the mutex locking because it uses member functions that are also usable outside initialization during normal function.

I think that the problem is a deadlock between the scheduler as seen in the call stack of main() thread and the other thread (probably) spawned by the scheduler. The deadlock seems to happen before main() is actually executed.

I would appreciate any advice as to how to fix/resolve the deadlock.

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

At the point of the deadlock there are two threads in the process:

Not Flagged >   6408    0   Main Thread Main Thread msvcr110d.dll!Concurrency::details::SchedulerBase::SchedulerBase    Normal
Not Flagged     7600    0   Worker Thread   ntdll.dll!_TppWaiterpThread@4() ntdll.dll!_NtDelayExecution@8   Normal

Here is the call stack of main() thread:

    ntdll.dll!_NtWaitForKeyedEvent@16() Unknown
    ntdll.dll!_TppWaitpSet@16() Unknown
    ntdll.dll!_TppSetWaitInterrupt@12() Unknown
    ntdll.dll!_RtlRegisterWait@24() Unknown
    kernel32.dll!_RegisterWaitForSingleObject@24()  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
    ntdll.dll!_LdrpCallInitRoutine@16() Unknown
    ntdll.dll!_LdrpRunInitializeRoutines@4()    Unknown
    ntdll.dll!_LdrpInitializeProcess@8()    Unknown
    ntdll.dll!__LdrpInitialize@8()  Unknown
    ntdll.dll!_LdrInitializeThunk@8()   Unknown

The second thread's call stack is short:

>   ntdll.dll!_NtDelayExecution@8() Unknown
    ntdll.dll!__LdrpInitialize@8()  Unknown
    ntdll.dll!_LdrInitializeThunk@8()   Unknown

EDIT 1:

WinDbg confirms that it is loader lock issue:

PRIMARY_PROBLEM_CLASS:  APPLICATION_HANG_HungIn_LoaderLock

解决方案

It seems that using QueueUserAPC() to queue initialization is always executed before main() but out of the dreaded loader lock. This looks like a solution to my problem.

EDIT 1

After some testing it seems that the APC method works if I queue the APC from DllMain() but it does not work if I queue the APC from a ctor of a static global instance of a class. IOW, using the APC is not uniformly usable across all possible combinations of compilers and build modes for me.

这篇关于C ++ 11 std :: mutex在Visual Studio 2012死锁时从DllMain()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆