【发布时间】:2010-12-13 21:11:27
【问题描述】:
似乎当在DLL_PROCESS_ATTACH 上从 DllMain 中创建一个线程时,它不会在所有 dll 都被加载之前开始。因为我需要确保线程在继续之前运行,所以我遇到了死锁。有什么办法可以强制线程启动吗?
【问题讨论】:
标签: winapi dll multithreading
似乎当在DLL_PROCESS_ATTACH 上从 DllMain 中创建一个线程时,它不会在所有 dll 都被加载之前开始。因为我需要确保线程在继续之前运行,所以我遇到了死锁。有什么办法可以强制线程启动吗?
【问题讨论】:
标签: winapi dll multithreading
您不应该从 DLLMain 执行任何 API 调用,尤其是对于创建线程或窗口之类的事情。 Raymond Chen 已经写过很多次了。这里是one,特别相关。
【讨论】:
DllMain 中调用等待函数非常糟糕,无论您在等待什么样的对象。通常,任何从 DLL 执行代码的线程都需要对该 DLL 有一个引用计数,而不是从它下面映射出的代码。这可以防止问题发生,因为只要线程正在运行,DllMain 就不会被调用(用于进程分离)。
CreateThread 可以安全地从DllMain 调用(假设您可以将其挂起并且不调用任何等待函数),但这仍然是一个坏主意,因为正是Raymond 的博文中提到的原因:如果您的 DLL 被其他一些依赖 DLL 短暂加载和卸载,您不希望在这种情况下创建不必要的资源(如线程)。
DllMain 调用CreateThread 是安全的(即使不推荐)。
你的线程是做什么的?
如果您试图将内容移动到第二个线程以避免限制您在 DllMain 中可以执行的操作,那么运气不好。这些不是对 DllMain 可以做什么的限制,它们是对 DllMain 运行时可以做什么的限制(并持有加载程序锁)。如果您的线程需要获取加载程序锁,它将等到第一个线程完成使用它。如果您的线程不需要加载程序锁,我不明白为什么它不能立即继续......但是没有不需要加载程序锁的线程。 Windows 必须在您的线程开始运行之前向所有 DLL 发送 DLL_THREAD_ATTACH 消息,这意味着它还调用您自己的 DllMain,并且 Windows 可以防止重新进入。
没有办法解决这个问题。线程在 DLL_THREAD_ATTACH 处理之后才能启动,并且当您的第一个线程在 DllMain 中时,这不会发生。唯一可能的解决方法是启动一个新进程(它有一个独立的加载程序锁,不会阻塞等待你的进程)。
【讨论】:
DLL_PROCESS_ATTACH 消息期间,我尝试了一个简单的练习,即在DLLMain() 中使用CreateThread() 来实现一个非常简单的工作函数。线程函数使用Sleep() 1000 毫秒。一切正常。我可以看到来自执行DLL_PROCESS_ATTACH 的初始线程和在附加处理期间创建的线程的DLL_THREAD_ATTACH 消息和DLL_THREAD_DETACH 消息。然而,这个工作线程除了Sleep() 之外什么也没做。 Kernel32.dll 调用应该没问题。使用 VS 2005 Windows 7 测试。
没有。您不应该从 DllMain 调用 CreateThread(或任何变体)。尝试同步将导致死锁。你到底想做什么?
【讨论】:
如果你这样做,你就是在自找麻烦。您不应(直接或间接)对 dll 之外的函数(包括 C 库调用等)进行任何调用。
如果您无法更改您拥有的 DLL(例如,您没有源代码),那么如果您的 DLL 在其余部分之后动态加载,您可能可以摆脱这种情况您的依赖 DLL 已初始化。如果您可以避免这种方法,我不会推荐这种方法,因为找出依赖链并不总是微不足道的(例如,如果您的 dll 导致依赖 dll 通过 COM 或其他方式动态加载第三个)。
【讨论】: