所以,这就是我在说的:std很复杂。
在VS2013中,此简单程序将导致死锁。
#include <thread>
#include <windows.h>
void foo()
{
}
void initialize()
{
std::thread t(foo);
}
BOOL APIENTRY DllMain(HMODULE, DWORD reason, LPVOID)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
initialize();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
在DLLMain中创建线程是完全错误的吗?这不是真的。从Microsoft的文档“创建DLL的最佳实践”中:“如果不与其他线程同步,则可以创建线程。” 因此,CreateThread有效,_beginthreadex有效,boost :: thread有效,但std :: thread不起作用。这是调用堆栈:
ntdll.dll!_NtWaitForSingleObject@12()
KernelBase.dll!_WaitForSingleObjectEx@12()
msvcr120d.dll!Concurrency::details::ExternalContextBase::Block() Line 151
msvcr120d.dll!Concurrency::Context::Block() Line 63
msvcr120d.dll!Concurrency::details::_Condition_variable::wait(Concurrency::critical_section & _Lck) Line 595
msvcp120d.dll!do_wait(_Cnd_internal_imp_t * * cond, _Mtx_internal_imp_t * * mtx, const xtime * target) Line 54
msvcp120d.dll!_Cnd_wait(_Cnd_internal_imp_t * * cond, _Mtx_internal_imp_t * * mtx) Line 81
msvcp120d.dll!std::_Cnd_waitX(_Cnd_internal_imp_t * * _Cnd, _Mtx_internal_imp_t * * _Mtx) Line 93
msvcp120d.dll!std::_Pad::_Launch(_Thrd_imp_t * _Thr) Line 73
mod.dll!std::_Launch<std::_Bind<1,void,void (__cdecl*const)(void)> >(_Thrd_imp_t * _Thr, std::_Bind<1,void,void (__cdecl*const)(void)> && _Tg) Line 206
mod.dll!std::thread::thread<void (__cdecl&)(void)>(void (void) * _Fx) Line 49
mod.dll!initialize() Line 17
mod.dll!DllMain(HINSTANCE__ * __formal, unsigned long reason, void * __formal) Line 33
好的,std :: thread将“与其他线程同步”。
但为什么 ?
我希望在VS2015中再也不会发生这种情况,我还没有进行测试。
的规范std::thread
包含以下要求(N4527§30.3.1.2[thread.thread.constr] / 6):
同步:构造函数的调用完成与副本的调用开始同步
f
。
(f
将在新创建的线程上执行的可调用实体在哪里。)
std::thread
在新线程开始执行线程过程之前,的构造函数无法返回。创建新线程时,在调用线程过程之前,将为调用每个已加载DLL的入口点DLL_THREAD_ATTACH
。为此,新线程必须获取加载程序锁。不幸的是,您现有的线程已经持有了加载程序锁。
因此,您将陷入僵局:现有线程无法释放加载程序锁,直到新线程开始执行线程过程为止,但是新线程无法执行线程过程,直到它能够获取现有线程持有的加载程序锁为止。
请注意,文档明确建议不要从DLL入口点创建线程:
您绝对不应从内部执行以下任务
DllMain
:[...]致电CreateThread
。如果您不与其他线程同步,则可以创建线程,但是这样做很冒险。
(该页面上有一长串的事情,这些事情不应该从DLL入口点完成;这只是其中之一。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句