在前一篇文章《DllMain()限入死锁问题分析 (二)》里,我们分析了LoadLibrary()与子线程访问PebLdr的目的,知道它们要进入同一关键区的原因所在。
下一个问题是,为什么在子线程要进入该关键区时,LoadLibrary()还没有退出关键区?正常情况下LoadLibrary()何时会退出关键区?
继续详细分析ntdll!LdrpLoadDll()函数,发现它在退出关键区之前,做的最主要的一件事是"call ntdll!LdrpRunInitializeRoutines"。根据前面分析死锁现场时找到的主线程栈回溯,可以知道LdrpRunInitializeRoutines函数最终会调用被加载模块的DllMain()函数。因此,结论就很清晰了,DllMain()被调用之前,主线程就进入了关键区,DllMain()返回以后,主线程才会退出关键区,因此在DllMain()函数中,但凡有需要进入同一关键区的操作,就会引起死锁。
如果仔细阅读MSDN中有关DllMain()的描述,可以找到相关的描述。
(URL:http://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx#general_best_practices)