清除DLL中的线程:

清除DLL中的线程:

好的。首先,让我们讨论几个小问题:

正如大卫在评论中提到的,()而不是CreateThread()。类似地,在任何当前支持的Visual和Windows版本上使用ExitThread()或类似的,而不是使用_endthreadex()也很好。尽管MSDN的那篇文章说了什么,可以使用TerminateThread()。人们还普遍认为,只要您了解加载程序锁所隐含的限制,在DllMain的DLL_PROCESS_ATTACH处理中使用CreateThread()是可以的。但是,如果您能够使用适当的初始化例程而不是DllMain (在您的情况下),那就更好了。因此,如果我正确理解了您的情况,可以总结如下:

DLL需要一个或多个后台线程。可执行文件在没有警告的情况下卸载DLL。有点傻,但那不是你的错。幸运的是,这不是不可能处理的。

如果在可执行文件认为已卸载DLL之后线程继续运行是可以接受的,则可以使用FreeLibraryAndExitThread()模式。在初始化函数中,以及在其他创建线程的地方,调用GetModuleHandleEx()以增加DLL引用计数。这样,当可执行文件调用FreeLibrary()时,如果任何线程仍在运行,则DLL实际上不会被卸载。线程通过调用FreeLibraryAndExitThread()退出,保持引用计数。

但是,这种方法可能不能直接满足您的需要,因为它不允许您检测可执行文件何时卸载了库,以便您可以向线程发出终止信号。

可能有更聪明的解决方案,但我建议使用辅助DLL。其思想是,帮助器DLL而不是主DLL跟踪线程引用计数,即每次创建后台线程时加载助手DLL,每次后台线程退出时卸载它。helper DLL只需要包含一个函数,该函数调用SetEvent(),然后调用FreeLibraryAndExitThread()。

当通知后台线程DLL正在卸载时,它会清理,然后调用helper DLL来设置事件并退出该线程。设置事件后,主DLL的分离例程知道线程不再从主DLL运行代码。一旦每个后台线程都完成了清理,主DLL卸载就安全了--线程仍然在运行并不重要,因为它们运行的代码来自助手DLL,而不是主DLL。当最后一个线程调用FreeLibraryAndExitThread()时,helper DLL将自动卸载。

再看一遍,大概一年后,可能会更安全:让主DLL只包含初始化函数和程序正在调用的任何其他函数,再加上一个DllMain,它指示后台线程退出,并有一个包含其他所有内容的辅助DLL。

特别是,如果辅助DLL包含后台线程所需的所有代码,则主DLL在后台线程仍在运行时卸载是安全的。

此变体的优点是,当后台线程看到要退出的信号时,主DLL是否已经卸载并不重要,因此您的DllMain函数在保持加载程序锁时不必等待。这样,如果某个后台线程无意中做了一些需要加载程序锁定的事情,进程就不会死锁。

作为相同想法的变体,如果您真的不想在CRT线程上使用FreeLibraryAndExitThread(),则可以在辅助DLL中设置一个额外的线程来协调卸载。这个线程将使用CreateThread()启动,不会使用任何CRT函数,因此毫无疑问,它通过FreeLibraryAndExitThread()退出是安全的。它的唯一责任是在卸载辅助DLL之前等待所有其他线程退出。

没有必要再区分CRT线程和非CRT线程了,但是如果您想严格遵守规则(如文档所示),这将是一种方法。

相关推荐

[交流]175日常选魔王还是龙宫
Bet体育365提款不到账

[交流]175日常选魔王还是龙宫

📅 06-29 👁️ 3296
你知道杜卡迪最贵的摩托车是哪款吗?最贵一款达到45万
可更换镜头数码相机ZV-E10
63365

可更换镜头数码相机ZV-E10

📅 07-27 👁️ 2337