2009-11-06 208 views
9

看来,当一个线程是从DllMain在DLL_PROCESS_ATTACH上创建的,它将不会开始,直到所有的dll被加载完毕。由于我需要确保线程在我继续之前运行,所以我会陷入僵局。有什么办法强制线程启动?在DllMain中创建线程?

回答

10

你不应该做任何的API调用,特别是对于一些像自的DLLMain创建线程或窗口。 Raymond Chen已经写了很多次了,这里的one特别相关。

+10

CreateThread是您可以在DllMain中执行的少数几件事之一,因为它是对kernel32的调用,保证已经加载。 – 2010-02-06 18:24:53

+2

@Ben Voigt,但要非常小心,因为如果要求当前的DllMain调用等待新线程返回,很容易死锁。 – mloskot 2010-11-09 13:43:20

+0

@mloskot:无论你在等待什么样的对象,在DllMain中调用等待函数都很糟糕。通常,任何执行DLL代码的线程都需要在该DLL上引用计数,而不是从代码下面映射出代码。这可以防止问题发生,因为只要线程正在运行,DllMain就不会被调用(用于进程分离)。 – 2010-11-09 14:06:11

5

不可以。您不应该从DllMain调用CreateThread(或任何变量)。尝试同步会导致死锁。你究竟想要做什么?

Best Practices for Creating DLLs

+7

调用CreateThread没什么不妥,但是没有办法解决这个问题,直到在父线程中完成DllMain处理之后线程才会被挂起。 – 2010-02-06 18:32:28

0

如果你这样做,你就会遇到麻烦。你不应该直接或间接地调用你的dll之外的函数(包括C库调用等)。

如果你不能改变你有的DLL(例如你没有源代码),你可能会得到如果你的DLL动态加载后,其他依赖的DLL是初始化。如果你可以避免它,我不会推荐这种方法,因为找出依赖链并不总是微不足道的(例如,如果你的dll导致依赖dll通过COM或其他方式动态加载第三个)。

+2

这里的第一段是过度泛化。对你知道的DLL进行调用是完全正确的,因为事实已经在你之前加载了。一般情况下,在大多数情况下,这只意味着KERNEL32.DLL,这听起来像是一个严重的限制,但你可以用它来引导你摆脱这种情况。 – 2010-04-20 16:08:28

+2

http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx – 2010-04-20 16:33:24

+0

感谢Integer诗人。这正好回答了我来这里解决的问题。 – 2010-05-05 23:42:23

5

你的线程是做什么的?

如果您尝试将内容移动到第二个线程以避免限制您在DllMain中可以执行的操作,那就太难过了。这些并不限制DllMain可以执行的操作,它们限制了DllMain运行时(并保持加载器锁定)可以执行的操作。如果你的线程需要加载器锁,它将等待,直到第一个线程完成使用它。如果你的线程不需要加载器锁,我不明白为什么它不能立即继续下去......但是不存在不需要加载器锁的线程。 Windows必须在您的线程开始运行之前将DLL_THREAD_ATTACH消息发送给所有DLL,这意味着它也会调用您自己的DllMain,并且Windows可以防止再次入侵。

有没有办法解决这个问题。直到DLL_THREAD_ATTACH处理后,线程才能启动,并且在第一个线程位于DllMain内时不会发生。唯一可行的方法是开始一个新的进程(它有一个独立的加载程序锁定,不会阻止等待你的)。

+0

在处理DLL_PROCESS_ATTACH消息期间,我尝试了一个在'DLLMain()'中使用'CreateThread()'作为一个非常简单的工作函数的简单练习。线程函数使用'Sleep()'1000毫秒。一切正常。我可以看到来自执行'DLL_PROCESS_ATTACH'的初始线程和附加处理期间创建的线程的'DLL_THREAD_ATTACH'消息和'DLL_THREAD_DETACH'消息。然而这个工作线程除了睡眠()之外什么也没做。 Kernel32.dll调用应该没问题。经过VS 2005 Windows 7测试。 – 2016-02-21 18:39:24

+0

奇怪的是,这真的是解决问题的唯一答案。我不知道为什么OP决定接受一个不是的答案。 – IInspectable 2016-05-04 20:04:02