【问题标题】:Notification on thread destroy线程销毁通知
【发布时间】:2026-02-18 07:40:01
【问题描述】:

如果线程被销毁,是否可以得到通知?我已经在这里看到过这样的问题: Notification when a thread is destroyed

答案是:DLL_THREAD_DETACH,但在 TerminateThread 的情况下它不会被调用。 所以,我的问题是,是否有可能检测到终止?我不想阻止它,只是在我的任何线程被破坏时收到通知。我不一定要使用 DllMain,任何解决方案都会很棒!

我在一个 DLL 中工作,它被注入到我的主应用程序中,所以我不能使用 WaitForSingleObject,因为它会挂起主可执行文件。

感谢您的每一个回答。

(P.s.:为了理解,我的 dll 的工作方式如下:主应用程序加载 dll,在 DLL_PROCESS_ATTACH 上,我打开了一些线程。)

编辑: 我忘记了,我使用的是 windows 和 Visual Studio 2013。

编辑 2: 我来了,禁用线程库调用,没用。我的意思是它不像我想的那样工作:) /我删除了那部分,所以它不会误导任何人/

【问题讨论】:

  • 但 DisableThreadLibraryCalls() 禁用 DLL_THREAD_ATTACH 和 DLL_THREAD_DETACH 通知。所以,你永远不会看到 DLL_THREAD_DETACH。
  • 即使我启用它们,它也不会调用,所以我不再需要它了。还是我错了?
  • 这个要求真的没有任何意义。如果您的 DLL 启动了一个线程,并且有人在外部杀死了该线程,那么您对此无能为力,该线程就消失了。检测到这一点的唯一方法是监视被杀死的线程。但是,怎样才能阻止攻击者杀死监视器呢?您将不得不求助于使用线程心跳并检测心跳何时停止,或者在每个进程中挂钩TerminateThread() 的每次出现,以便您可以检查您的 DLL 的线程 ID 之一是否是目标。我没有看到任何其他解决方法。
  • DllMain 中创建线程几乎肯定迟早会死锁。如果您想了解原因,请阅读Dynamic-Link Library Best Practices
  • @IInspectable:实际上,该文章似乎非常模糊地说明了为什么或在什么情况下创建线程可能是一个问题。它关于这个主题的所有内容(我能找到)是“如果你不与其他线程同步,创建一个线程可以工作,但它是有风险的。”

标签: c++ multithreading winapi callback notifications


【解决方案1】:

我建议让您的 DLL 产生自己的工作线程,然后可以在您需要监视的线程的句柄上使用 WaitForSingleObject()。当线程终止时,即使由TerminateThread() 终止,也会发出句柄信号。最好使用WaitForMultipleObjects(),这样您的DLL 就可以在工作线程需要终止时发出信号,例如使用CreateEvent()SetEvent()。这样,工作线程就不需要定期运行繁忙的循环来寻找终止条件。

【讨论】:

  • 谢谢,但让我稍微解释一下:这将是一种自卫,其中这些线程非常重要,不应该关闭。如果终止,我想退出整个过程。通过制作另一个线程没有任何帮助。他们可以轻松地同时终止所有线程(我的意思是所有由特定 DLL 启动的线程)这就是为什么我想要某种不能轻易终止的回调。
  • 您认为应用程序如何识别哪些线程属于您的 DLL,哪些属于其他模块,甚至是操作系统?在同一进程中运行的线程不知道是哪些模块创建了它们。应用程序可以安全地挑选出您的 DLL 线程的唯一方法是挂钩到 CreateThread() 本身并查看调用堆栈上的返回地址,以查看它是否在您的 DLL 使用的地址空间内。
  • 是的,大多数人都这么说是因为他们就是这样学的。好吧,我并不是说有 120% 确定的方法可以获取,但是通过一些“hack”,您可以检测到哪个模块启动了线程。当有人手动映射一个模块或以某种方式隐藏它时,问题就开始了,但我会找到一种方法来检测它:) 所以,多合一:找出哪个模块启动了线程是可能的而且并不难(你必须查看 PE 结构和偏移量)。
  • 您可以通过使用线程池来混淆您的监控代码(甚至可能是您的主代码)。如果应用程序也直接或间接地使用线程池,则 DLL 代码将与应用程序共享相同的线程。
【解决方案2】:

我刚刚阅读了有关 DllMain() 的文档:

如果您通过调用 TerminateThread 来终止线程,则该线程的 DLL 线程不接收 DLL_THREAD_DETACH 通知。

因此,如果线程终止,您将不会收到 DLL_THREAD_DETACH。 关于 DLL_THREAD_DETACH 的重要考虑是,如果“线程正在干净地退出”,您将收到此通知

【讨论】:

  • 如果你真的需要有关于 TerminateThread() 的通知,那么你需要拦截这个系统调用(如果需要,使用 GetModuleFileName())等等
  • 我明白你的意思,但是如果线程没有干净地退出,我想得到通知。这样 DllMain 解决方案就不起作用了。
  • 如果线程没有干净地退出,您将无法通过 DllMain() 获得通知。而且没有办法让 DllMain() 通知以其他方式工作
  • 我不在乎我是否不使用 DllMain。我刚才提到了,我试过了。我愿意使用任何其他方法,唯一重要的是“结束”,如果它被不干净地终止,就会得到通知。 (也许以某种方式回调?)
  • 不,唯一的解决方案是捕获对 TerminateThread() 的系统调用
【解决方案3】:

您可以运行一个观察者线程来监控您需要的所有线程并生成“no-more-the-thread”通知。

【讨论】:

  • 谢谢,但让我稍微解释一下:这将是一种自卫,其中这些线程非常重要,不应该关闭。如果终止,我想退出整个过程。通过制作另一个线程没有任何帮助。他们可以轻松地同时终止所有线程(我的意思是所有由特定 DLL 启动的线程)这就是为什么我想要某种不能轻易终止的回调。