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.
我可以自己验证这个问题:在这种情况下终止线程会导致内存分配问题(以及其他问题),但修复该情况会同时解决问题。
问题
所以,我想在每次使用 terminateThread()
后检查这个内部状态。如果 terminateThread()
导致 kernel32.dll 中进程的内部状态出现问题,我想引发异常 - 并在登录到用户后终止进程(除非仍然可以修复内部状态)。
这可行吗?也许通过找到相关状态变量的地址(或类似的东西 - 通过匹配 kernel32 的 pdb 文件或其他方式)?这种情况对我来说很糟糕——如果我不能解决它,我要么必须省略 threapool 的终止选项,要么只保留线程本身。任何提示将不胜感激!
是否有任何其他 win32 函数导致类似问题?
一个。当线程调用了绝对不会 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
时弄乱你的应用程序
- 如果您使用 b.
中解释的相同方式删除了其余代码
- 如果您没有删除 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 时退出。
备注
在没有收到任何答案后,我根据发现的内容回答了自己的问题。因此,它可能包含一些错误信息。如有不妥请指正
我已经为用户可用的线程编写了一个带有终止选项的线程池。如中所述
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.
我可以自己验证这个问题:在这种情况下终止线程会导致内存分配问题(以及其他问题),但修复该情况会同时解决问题。
问题
所以,我想在每次使用
terminateThread()
后检查这个内部状态。如果terminateThread()
导致 kernel32.dll 中进程的内部状态出现问题,我想引发异常 - 并在登录到用户后终止进程(除非仍然可以修复内部状态)。这可行吗?也许通过找到相关状态变量的地址(或类似的东西 - 通过匹配 kernel32 的 pdb 文件或其他方式)?这种情况对我来说很糟糕——如果我不能解决它,我要么必须省略 threapool 的终止选项,要么只保留线程本身。任何提示将不胜感激!
是否有任何其他 win32 函数导致类似问题?
一个。当线程调用了绝对不会 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
时弄乱你的应用程序- 如果您使用 b. 中解释的相同方式删除了其余代码
- 如果您没有删除 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 时退出。
备注
在没有收到任何答案后,我根据发现的内容回答了自己的问题。因此,它可能包含一些错误信息。如有不妥请指正