[英]C++11 std::mutex in Visual Studio 2012 deadlock when locked from DllMain()
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. 当从
DllMain()
锁定std::mutex
时,我看到std::mutex
出现死锁。这是一个最小的DLL测试用例,它对我来说是个问题。 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. 我认为问题是在
main()
线程的调用堆栈和调度程序产生的另一个线程(可能)之间出现了调度程序之间的死锁。 The deadlock seems to happen before main()
is actually executed. 死锁似乎发生在
main()
实际执行之前。
I would appreciate any advice as to how to fix/resolve the deadlock. 对于如何解决/解决死锁问题,我将不胜感激。
Simple DLL: 简单的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: 这是
main()
线程的调用堆栈:
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: 编辑1:
WinDbg confirms that it is loader lock issue: WinDbg确认这是加载程序锁定问题:
PRIMARY_PROBLEM_CLASS: APPLICATION_HANG_HungIn_LoaderLock
Check the Best Practices for Creating DLLs document: 查看创建DLL的最佳做法文档:
You should never perform the following tasks from within DllMain:
您永远不要在DllMain中执行以下任务:
- Call LoadLibrary or LoadLibraryEx (either directly or indirectly).
调用LoadLibrary或LoadLibraryEx(直接或间接)。 This can cause a deadlock or a crash.
这可能导致死锁或崩溃。
- Synchronize with other threads.
与其他线程同步。 This can cause a deadlock.
这可能导致死锁。
It seems that using QueueUserAPC()
to queue initialization is always executed before main() but out of the dreaded loader lock. 似乎总是在main()之前执行
QueueUserAPC()
进行队列初始化,但要在可怕的加载器锁之外执行。 This looks like a solution to my problem. 这看起来像解决我的问题。
EDIT 1 编辑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. 经过一些测试后,如果我从
DllMain()
排队APC,则APC方法似乎可以工作,但是如果我从类的静态全局实例的ctor排队APC,则APC方法不能工作。 IOW, using the APC is not uniformly usable across all possible combinations of compilers and build modes for me. IOW,对于我来说,并不是在所有可能的编译器和构建模式组合中都统一使用APC。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.