简体   繁体   English

如何停止线程并将其寄存器刷新到堆栈中?

[英]How do you stop a thread and flush its registers into the stack?

I'm creating a concurrent memory reclamation algorithm in C++. 我正在用C ++创建并发内存回收算法。 Periodically, the stacks of executing mutator threads need to be inspected, so that I can see what references the threads are currently holding. 需要定期检查执行mutator线程的堆栈,以便我可以看到线程当前持有的引用。 In the process of doing this, I need to also check the registers of the mutator thread to check any references that might be in there. 在执行此操作的过程中,我还需要检查mutator线程的寄存器以检查可能存在于其中的任何引用。

Clearly many JVM's and C# vm's have no problem doing this as part of their garbage collection cycles. 很明显,许多JVM和C#vm在执行此操作时都没有问题,因为它们是垃圾收集周期的一部分。 However, I haven't been able to find a definitive solution to this issue. 但是,我无法找到解决此问题的最终解决方案。

I can't quite tease apart what is going on in the Bohem garbage collector in order to inspect the root set, if you can (or know how its done), I'd really like to know. 我不能完全区分Bohem垃圾收集器中发生的事情,以便检查根集,如果可以(或知道它是如何完成的),我真的很想知道。

Ideally I would be able to cause the mutator thread to be interrupted, and execute a piece of handler code which would report it's PC and also flush any register-based references into the stack, and then perhaps help finish the collection cycle. 理想情况下,我可以使mutator线程被中断,并执行一段处理程序代码,该代码将报告它的PC并将任何基于寄存器的引用刷新到堆栈中,然后可能有助于完成收集周期。 I believe that most compilers in most systems will automatically flush the registers when interrupt or signal handlers are called, but I'm not clear on the specifics, or how to access that data. 我相信大多数系统中的大多数编译器会在调用中断或信号处理程序时自动刷新寄存器,但我不清楚具体细节或如何访问该数据。 It seems that separate stacks might be used for interrupt and signal handlers. 似乎单独的堆栈可能用于中断和信号处理程序。 Additionally, I can't find any information about how to target a particular thread, or how to send a signal. 此外,我找不到有关如何定位特定线程或如何发送信号的任何信息。 Windows does not seem to support this form of signaling anyway, and I would like my system to run on both Linux and Windows on x86-64 processors. Windows无论如何似乎都不支持这种形式的信令,我希望我的系统能够在x86-64处理器上的Linux和Windows上运行。

Edit: SuspendThread() is used in some situations, although safepoints seem to be preferred. 编辑: SuspendThread()在某些情况下使用,虽然安全点似乎是首选。 Any ideas on why? 有什么想法吗? Is there any way to deal with long-lasting I/O waits or other waits for kernel code to return? 有没有办法处理持久的I / O等待或其他等待内核代码返回?

I thought this was a very interesting question, so I dug into it a bit. 我认为这是一个非常有趣的问题,所以我稍微挖了一下。 It turns out that the Hotspot JVM uses a mechanism called "safepoints" which cause the threads of the JVM to cooperatively all stop themselves so that the GC can begin. 事实证明,Hotspot JVM使用一种称为“安全点”的机制,这种机制使JVM的线程协同工作,所有这些机制都会自行停止,以便GC可以开始。 In other words, the thread initiating GC doesn't forcibly stop the other threads, the other threads voluntarily suspend themselves by various clever mechanisms. 换句话说,启动GC的线程不强制停止其他线程,其他线程通过各种聪明的机制自愿挂起自己。

I don't believe the JVM scans registers, because a safepoint is defined such that all roots are known (I presume this means in memory). 我不相信JVM扫描寄存器,因为定义了一个安全点,所有根都是已知的(我认为这意味着在内存中)。

For more information see: 有关更多信息,请参阅

In regards to your desire to "interrupt" all threads, according to the slide deck I referenced above, thread suspension is "unreliable on Solaris and Linux, eg, spurious signals." 关于你想要“中断”所有线程的愿望,根据我上面提到的幻灯片,线程暂停“在Solaris和Linux上是不可靠的,例如,虚假信号”。 I'm not sure what mechanism even exists for thread suspension that the slides would be referring to. 我不确定滑块所指的线程悬挂甚至存在什么机制。

On windows you should be able to get this done use SuspendThread (and ResumeThread) along with GetThreadContext (as Hans mentioned). 在Windows上,您应该能够使用SuspendThread (和ResumeThread)以及GetThreadContext (如Hans所提到的)完成此操作。 All of these functions take handles to the specific thread you intend to target. 所有这些函数都将句柄处理到您要定位的特定线程。

To get a list of all threads in the current process, see this (toolhlp32 works on x64, despite its bad naming scheme...). 要获取当前进程中所有线程的列表,请参阅 (toolhlp32适用于x64,尽管其命名方案不正确......)。

As a point of interest, one way to flush registers to the stack on x86 is to use the PUSHAD assembly instruction. 作为一个兴趣点,在x86上将寄存器刷新到堆栈的一种方法是使用PUSHAD汇编指令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM