std :: thread在DLLMain中导致死锁

阿曼江

所以,这就是我在说的: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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章