如何停止线程并将其寄存器刷新到堆栈中? 我在C++中创建了一个并发内存回收算法。需要定期检查执行mutator线程的堆栈,以便查看线程当前持有的引用。在此过程中,我还需要检查mutator线程的寄存器,以检查其中可能存在的任何引用

如何停止线程并将其寄存器刷新到堆栈中? 我在C++中创建了一个并发内存回收算法。需要定期检查执行mutator线程的堆栈,以便查看线程当前持有的引用。在此过程中,我还需要检查mutator线程的寄存器,以检查其中可能存在的任何引用,c++,multithreading,memory-management,concurrency,garbage-collection,C++,Multithreading,Memory Management,Concurrency,Garbage Collection,显然,许多JVM和C#vm在垃圾收集周期中这样做没有问题。然而,我还没有找到这个问题的最终解决方案 为了检查根集,我不能完全区分Bohem垃圾收集器中发生了什么,如果可以(或者知道它是如何完成的),我真的很想知道 理想情况下,我将能够中断mutator线程,并执行一段处理程序代码,该代码将报告它的PC,并将任何基于寄存器的引用刷新到堆栈中,然后可能有助于完成收集周期。我相信大多数系统中的大多数编译器在调用中断或信号处理程序时会自动刷新寄存器,但我不清楚具体细节,也不清楚如何访问这些数据。中断和信

显然,许多JVM和C#vm在垃圾收集周期中这样做没有问题。然而,我还没有找到这个问题的最终解决方案

为了检查根集,我不能完全区分Bohem垃圾收集器中发生了什么,如果可以(或者知道它是如何完成的),我真的很想知道

理想情况下,我将能够中断mutator线程,并执行一段处理程序代码,该代码将报告它的PC,并将任何基于寄存器的引用刷新到堆栈中,然后可能有助于完成收集周期。我相信大多数系统中的大多数编译器在调用中断或信号处理程序时会自动刷新寄存器,但我不清楚具体细节,也不清楚如何访问这些数据。中断和信号处理程序似乎可以使用不同的堆栈。此外,我找不到关于如何瞄准特定线程或如何发送信号的任何信息。Windows似乎无论如何都不支持这种形式的信号,我希望我的系统在x86-64处理器上的Linux和Windows上运行


Edit:SuspendThread()在某些情况下使用,但safepoints似乎是首选。你知道为什么吗?有没有办法处理长时间的I/O等待或其他等待内核代码返回的等待?

我认为这是一个非常有趣的问题,所以我深入研究了一下。事实证明,热点JVM使用了一种称为“安全点”的机制,该机制会导致JVM的线程协同停止,以便GC可以开始。换句话说,启动GC的线程不会强制停止其他线程,其他线程通过各种巧妙的机制自动挂起自己

我不相信JVM会扫描寄存器,因为safepoint的定义使得所有根都是已知的(我想这意味着在内存中)

有关更多信息,请参阅:

  • --它定义了安全点
  • --热点中实现安全点的源
  • 详细描述了安全点(请看10张左右的幻灯片)

关于您想要“中断”所有线程的愿望,根据我上面提到的幻灯片组,线程挂起“在Solaris和Linux上不可靠,例如,虚假信号”。我不确定幻灯片所指的线程挂起机制是什么。

在windows上,您应该能够使用它来完成这项任务(和ResumeThread)以及(正如Hans提到的)。所有这些函数都会将句柄带到您要针对的特定线程

要获取当前进程中所有线程的列表,请参阅(toolhlp32在x64上工作,尽管其命名方案不好…)


有趣的是,在x86上将寄存器刷新到堆栈的一种方法是使用
PUSHAD
汇编指令。

不使用刷新,收集器只检查寄存器中的对象引用。在Windows中使用GetThreadContext()很容易做到。嗯,
GetThreadContext
根本不读取寄存器。它读取寄存器保存到上一次上下文开关停用该特定线程时的内存。@coolkid:编译器不会在发生中断时刷新寄存器(也不会发出代码来执行此操作),这是CPU本身的一个功能。我不认为从线程外(没有@josh haberman的safepoints)将寄存器刷新到堆栈中会起作用,因为编译器可以对变量使用寄存器,而无需为其分配任何堆栈空间。相反,您应该获取寄存器值并检查它们以及堆栈。“通常”将寄存器刷新到堆栈的方法是通过中断。@BenVoigt:afaiak windows在内核模式之外不提供这种功能(我可能错了)。这是从用户模式访问内核服务的传统方式,是通过软件中断。x86现在有
sysenter
指令,这在某种程度上简化了事情,但我相信它仍然执行相同的寄存器保存。但实际上,我只是对您的声明进行了评论,即
PUSHAD
是唯一的保存方式寄存器到堆栈,因为它不是。顺便说一句,上下文切换是由中断(I/O或计时器)引起的这就是线程状态如何在内存中结束,以便
gethreadcontext
访问。@BenVoigt:那么,修复了我的文本。那么,要使用gethreadcontext,我正在检查的线程会发生什么?它必须先休眠自己,还是我可以调用gethreadcontext,它会中断线程并存储寄存器?嗯如果是这种情况,那么您如何处理这样一个事实:如果线程正在等待IO,或者操作系统只是有许多相互竞争的进程,那么它可能在一段时间内无法调度?我不想为此而暂停。如果您查看上面指向safepoint.cpp的链接,评论说当前被阻止的任何线程都将不被允许o继续,直到safepoint操作完成(就像他们已经在safepoint一样)。我猜在GC开始之前,所有可运行线程都必须进行调度,以便它们可以在已知状态下暂停,这可能是无法避免的。哎呀!如果其中一个线程正在等待IO或正在睡觉等待释放锁,那么这可能需要很长时间。有人知道这是否真的是这样吗?关于.NET的GC谈论的是.NET尝试使用safepoints大约1s,然后放弃并使用SuspendThread()调用。非常有趣。对于等待I/O的线程,我认为您不必等待它们被调度。它们被放入