get/check 进程 win32 的内部 kernel32 状态(为了安全使用 TerminateThread )

get/check inner kernel32 state for process win32 (for safe usage of TerminateThread )

我已经为用户可用的线程编写了一个带有终止选项的线程池。如中所述 Documentation of API terminateThread(),

If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.

我可以自己验证这个问题:在这种情况下终止线程会导致内存分配问题(以及其他问题),但修复该情况会同时解决问题。

问题

  1. 所以,我想在每次使用 terminateThread() 后检查这个内部状态。如果 terminateThread() 导致 kernel32.dll 中进程的内部状态出现问题,我想引发异常 - 并在登录到用户后终止进程(除非仍然可以修复内部状态)。

    这可行吗?也许通过找到相关状态变量的地址(或类似的东西 - 通过匹配 kernel32 的 pdb 文件或其他方式)?这种情况对我来说很糟糕——如果我不能解决它,我要么必须省略 threapool 的终止选项,要么只保留线程本身。任何提示将不胜感激!

  2. 是否有任何其他 win32 函数导致类似问题?

  3. 一个。当线程调用了绝对不会 return?

    的阻塞 kernel32 函数时,为自己留一个线程是否安全?

    b。如果 win32 函数 returns 和 lambda 函数被破坏了会怎样?

我为什么要问这个? (补充资料)

我的项目中有一个自定义线程池,我在其中调用一些有时可能永远阻塞的 win32 API。因此,我使用超时调用它们。当达到该超时时,我调用 terminateThread() 并让我的线程池 return "unsucessfull call state".

有时,我当前的应用程序会陷入僵局。我发现这个死锁发生在线程池中,所以我正在寻找 terminateThread() 的替代方法(例如按照我在问题中描述的那样离开线程)或尝试修复内部状态,或者至少验证 terminateThread() 是否是我的死锁的根源。

我也想在其他项目中重用这个线程池,所以我应该确保它安全。

更新:问题已修复。

我在我的应用程序中发现了错误: 当我的线程池中的超时时间已经很低(大约 200 毫秒)时,它实际上是对 terminateThread() 的调用。 线程在没有阻塞的时候被杀死了(即,如果超时时间更长,它会工作并且 returned 正确)。 从内核堆栈跟踪中,我发现在内核模式下,线程终止时互斥量被锁定,而线程退出时,其他线程已经在等待该互斥量。

问题最初似乎是通过将最小超时时间增加到 1000 毫秒而消失的,但我对此并不满意: 我的解决方案是在达到超时时在堆上创建 lambda,将 lambda 和线程留给自己而不终止,并将其添加到 _ToTerminateThreads 的列表中。 列表每 10 分钟终止一次(等待 10 分钟,复制列表,再等一分钟,然后终止线程并删除 lambda)。

尽管如此,经过测试和数小时的调试后,我还是遇到了堆损坏问题。 最后我发现了以下内容: 我留待删除的线程 写入用户函数使用的内存(传递给线程池) - 他们被释放了,因为线程池已经 returned。 这导致了最终的问题,所以最终的解决方案是将超时时间增加到安全的时间。

我建议所有需要此功能的人将其部署到子进程,并终止该进程而不是使用线程。

我将此问题悬而未决,因为主要的 4 个问题尚未得到解答。对于我的问题,我不再需要他们的答案,但他们可能对 Whosebug 的其他成员很有趣。

我的问题已解决,尽管它与 post 中的 3 个问题无关。 我尝试以相反的顺序回答它们:

  • ad 3.b.) 如果外部函数 returns 和您的本地 lambda 已被删除,则 cpu 不会知道这一点,并将尝试按照 CPU 指令处理该偏移量处的字节。这肯定会把你搞得一团糟,所以永远不要那样做!

  • ad 3.a.) 是的,如果你 100% 确定外部函数永远不会 return(否则它会在 return

    时弄乱你的应用程序
    1. 如果您使用 b.
    2. 中解释的相同方式删除了其余代码
    3. 如果您没有删除 lambda 或者它是一个 gobal 函数,它将 运行 可能正在编辑动态分配的内存(堆,而不是堆栈)的其余函数已被释放并导致堆损坏或只是编辑一些全局变量)。
  • ad 2.) 我用谷歌搜索了危险的 winapi 函数,除了 TerminateThread() 之外没有找到任何结果。 如果你知道一个,请添加评论或写另一个答案。

  • ad 1.) 对于 Microsoft 引用的进程的 checking/fixing 内部 kernel32 状态,我没有任何解决方案。 我认为阅读过 kernel32.dll 源代码的 Microsoft 人员应该回答这个问题。

除了这个 kernel32 状态,TerminateThread() 会导致很多其他问题(比如 resource/heap 分配、互斥锁、泄漏等等)所以除非你 100% 确定你在做什么,否则永远不要使用它正在做。

阅读评论中链接的@RichardCritten 文章:TerminateThread()

我的代码中的错误是什么?

我调用 TerminateThread() 的超时时间很短(300 毫秒)。 随机地,当一台机器资源不足时,该功能仍在运行(我的意思是非阻塞调用!)。 我终止了该函数,从而导致内核互斥锁被锁定。 这个锁定的互斥锁让所有其他线程等待 - 而不是在它们 returned 时退出。

备注

在没有收到任何答案后,我根据发现的内容回答了自己的问题。因此,它可能包含一些错误信息。如有不妥请指正