c++ - 获取/检查进程 win32 的内部 kernel32 状态(为了安全使用 TerminateThread )
问题描述
我已经为用户可用的线程编写了一个带有终止选项的线程池。如
API 文档中terminateThread()
所述,
如果目标线程在终止时正在执行某些 kernel32 调用,则线程进程的 kernel32 状态可能不一致。
我可以自己验证这个问题:在这种情况下终止线程会导致内存分配问题(以及其他问题),但修复该条件同时解决了问题。
问题
所以,我想在每次
terminateThread()
使用后检查这个内部状态。如果terminateThread()
在 kernel32.dll 中导致进程的内部状态出现问题,我想引发异常 - 并在登录到用户后终止进程(除非仍然可以修复内部状态)。这可行吗?也许通过找到相关状态变量的地址(或类似的东西 - 通过匹配 kernel32 的 pdb 文件或其他方式)?这种情况对我来说很糟糕——如果我无法解决它,我要么必须省略 threapool 的终止选项,要么只将线程留给自己。任何提示将不胜感激!
是否还有其他导致类似问题的win32功能?
一种。当它调用一个绝对永远不会返回的阻塞 kernel32 函数时,为它自己留下一个线程是否安全?
湾。如果 win32 函数返回而 lambda 函数已被销毁会怎样?
我为什么要问这个?(补充资料)
我的项目中有一个自定义线程池,我在其中调用了一些有时可能会永远阻塞的 win32 API。因此,我使用超时来调用它们。当达到超时时,我调用terminateThread()
并让我的线程池返回“不成功的调用状态”。
有时,我当前的应用程序会陷入僵局。我发现这个死锁发生在线程池中,所以我正在寻找替代方案terminateThread()
(例如按照我在问题中描述的那样离开线程)或尝试修复内部状态,或者至少验证是否terminateThread()
是根我的僵局。
我也想在其他项目中重用这个线程池,所以我应该让它安全。
更新:问题已修复。
我在我的应用程序中发现了错误:它实际上是terminateThread()
在我的线程池中的超时已经很低(大约 200 毫秒)时调用。线程在它没有阻塞的时候被杀死(即,如果有更长的超时时间,它会工作并正确返回)。从内核堆栈跟踪中,我发现在内核模式下,一个互斥锁在线程终止时被锁定,而当线程退出时,其他线程已经在等待该互斥锁。
通过将最小超时时间增加到 1000 毫秒,问题首先似乎消失了,但我对此并不满意:我的解决方案是在达到超时时在堆上创建 lambda,将 lambda 和线程留给自己而不终止,并且将其添加到_ToTerminateThreads
. 该列表每 10 分钟终止一次(等待 10 分钟,复制列表,再等待一分钟,然后终止线程并删除 lambdas)。
尽管如此,经过测试和数小时的调试后,我还是遇到了堆损坏。最后我发现了以下内容:我留待删除的线程写入了用户函数(已传递给线程池)使用的内存 - 由于线程池已返回,它们被释放。这导致了最终的问题,因此最终的解决方案是将超时增加到安全量。
我建议所有需要这种功能的人将其部署到子进程,并终止该进程而不是使用线程。
我保持这个问题是开放的,因为主要的 4 个问题还没有得到回答。对于我的问题,我不再需要他们的答案,但他们可能对 stackoverflow 的其他成员很感兴趣。
解决方案
我的问题已解决,尽管它与帖子中的 3 个问题无关。我尝试以相反的顺序回答它们:
ad 3.b.)如果一个外部函数返回并且您的本地 lambda 已被删除,cpu 将不知道这一点,并将尝试将该偏移处的字节作为 CPU 指令处理。这肯定会搞砸你,所以永远不要那样做!
ad 3.a.)是的,如果你 100% 确定外部函数永远不会返回,那么离开是安全的(否则返回时会弄乱你的应用程序
- 如果您使用b 中解释的相同方式删除了其余代码。
- 如果您没有删除 lambda 或者它是一个 gobal 函数,它将运行其余函数,这些函数可能正在编辑已被释放并导致堆损坏的动态分配内存(堆,而不是堆栈),或者只是编辑一些全局变量)。
广告 2.)我搜索了危险的 winapi 函数,除了
TerminateThread()
. 如果您知道一个,请添加评论或写另一个答案。广告 1.)我没有任何解决方案来检查/修复 Microsoft 所指进程的内部 kernel32 状态。我认为阅读过 kernel32.dll 源代码的微软人应该回答这个问题。
除了这个 kernel32 状态之外,TerminateThread()
还会导致许多其他问题(如资源/堆分配、互斥锁、泄漏等),所以除非你 100% 确定你在做什么,否则永远不要使用它。
阅读评论中链接的文章@RichardCritten:TerminateThread()
我的代码中的错误是什么?
我打电话TerminateThread()
的超时时间很短(300 毫秒)。随机地,当机器资源不足时,该功能仍在运行(我的意思是非阻塞调用!)。我终止了该函数,从而导致内核互斥锁被锁定。这个锁定的互斥锁使所有其他线程等待 - 当它们返回时不会退出。
评论
在没有收到任何答案后,我根据发现的内容回答了我自己的问题。因此,它可能包含一些错误信息。如果这有什么问题,请纠正我。
推荐阅读
- java - Java 8 到 openJdk 11 com.sun.org.apache.xml.internal.* 类型不可访问
- spring-boot - 如何将静态密钥库替换为 spring-boot-application 的动态密钥库
- r - 如何使用 mutate_at 将 sw_glance 应用于嵌套的时间序列数据帧?
- python - 将张量分配给多个切片
- python - 如何格式化带有千位分隔符和括号中的负数的数据透视表数字?
- r - 更改 ggplot2 中的图例标签
- microk8s - microk8s.enable dns 卡在 ContainerCreating
- arrays - 在 Nim 中定义空数组的问题
- assembly - 如果文件在 gnu 中太大,则组装失败
- msbuild - 为什么 ninja build 和 msbuild 不能使用超过大约 50%?