如何停止线程并将其寄存器刷新到堆栈中
How do you stop a thread and flush its registers into the stack?
我正在C++中创建一个并发内存回收算法。需要定期检查正在执行的赋值线程的堆栈,这样我就可以看到线程当前持有的引用。在执行此操作的过程中,我还需要检查赋值线程的寄存器,以检查其中可能存在的任何引用。
很明显,许多JVM和C#vm在垃圾回收周期中这样做是没有问题的。然而,我还没能找到解决这个问题的最终办法。
为了检查根集,我无法完全梳理Bohem垃圾收集器中发生了什么,如果可以的话(或者知道它是如何完成的),我真的很想知道。
理想情况下,我可以使赋值线程中断,并执行一段处理程序代码,报告它的PC,还可以将任何基于寄存器的引用刷新到堆栈中,然后可能帮助完成收集周期。我相信大多数系统中的大多数编译器在调用中断或信号处理程序时都会自动刷新寄存器,但我不清楚具体细节,也不清楚如何访问这些数据。中断和信号处理程序似乎可以使用单独的堆栈。此外,我找不到任何关于如何针对特定线程或如何发送信号的信息。Windows似乎无论如何都不支持这种形式的信号,我希望我的系统在Linux和Windows的x86-64处理器上运行。
编辑:SuspendThread()在某些情况下使用,尽管安全点似乎是首选。有什么想法吗?有什么方法可以处理长时间的I/O等待或内核代码返回的其他等待吗?
我觉得这是一个非常有趣的问题,所以我深入研究了一下。事实证明,Hotspot JVM使用了一种称为"安全点"的机制,该机制使JVM的线程协同地全部停止,以便GC可以开始。换句话说,启动GC的线程不会强制停止其他线程,其他线程会通过各种巧妙的机制自动挂起自己。
我不相信JVM扫描寄存器,因为定义了一个安全点,使得所有根都是已知的(我认为这意味着在内存中)。
有关更多信息,请参阅:
- HotSpot词汇表——定义安全点
- safepoint.cpp——HotSpot中实现安全点的源
- 详细描述安全点的幻灯片组(请参阅中的10张左右幻灯片)
关于"中断"所有线程的愿望,根据我上面提到的幻灯片组,线程挂起"在Solaris和Linux上是不可靠的,例如,虚假信号。"我不确定幻灯片所指的线程挂起机制是什么。
在windows上,您应该能够使用SuspendThread(和ResumeThread)以及GetThreadContext(如Hans所述)来完成这项工作。所有这些函数都将句柄带到要作为目标的特定线程。
要获得当前进程中所有线程的列表,请参阅此(toolhlp32适用于x64,尽管其命名方案不正确…)。
感兴趣的是,将寄存器刷新到x86上的堆栈的一种方法是使用PUSHAD
汇编指令。
- 算法问题:查找从堆栈中弹出的所有序列
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么调用堆栈数组会导致内存泄漏
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 堆栈和队列是否像C++中的数组一样传递?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 是否可以配置提升日志刷新?
- 如何在qt中同步应用程序和显示器的刷新率?
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 堆栈中大小变量输入错误 (C++)
- 堆栈问题(平衡表达式问题集)
- C++ 在堆栈中包含多态属性的类对象存储
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 在 C++ 中使用链表进行堆栈
- 如何停止线程并将其寄存器刷新到堆栈中