在GC期间,.NET中的线程暂停。如何通过CLR安全地暂停线程?通过像Win32 SuspendThread API这样残酷的方式停止线程会有什么风险?
答案 0 :(得分:7)
这是关于.NET Compact Framework,但我认为对于普通的.NET来说是正确的:http://blogs.msdn.com/b/abhinaba/archive/2009/09/02/netcf-gc-and-thread-blocking.aspx
在实际运行GC之前,CLR尝试进入“安全点”。每个线程都有一个与之关联的挂起事件,并且每个线程定期检查此事件。在启动GC之前,CLR枚举所有托管线程,并在每个线程中设置此事件。在线程检查并发现此事件集的下一个点,它会阻止等待事件重置(GC完成时会发生这种情况)。
答案 1 :(得分:5)
通常,线程1可以安全地暂停线程2,通过设置“请立即暂停”标志,执行线程2中的代码保证在有限的时间段内进行测试,然后暂停自己的安全点。它的执行。
在.NET CLR(无论如何都是这种情况)中,线程可以处于协作GC模式或抢占模式。在合作模式中,例如在运行托管代码方法时,线程偶尔会明确检查它是否应该产生。
相反,在抢占模式中,例如,当运行p调用的本机代码时,有时在CLR本身(MSCORWKS.DLL等)中,另一个线程(包括需要GC的另一个CLR线程)可以在任何指令边界单方面挂起第一个线程。
确实,这些可以结合起来。 CLR GC可以设置“请立即暂停”标志,然后等待一段时间,以防先占模式线程返回到协作模式(然后测试标志并暂停其线程)。如果在等待之后,抢先模式线程仍未暂停,则CLR(在另一个线程上)可能会单方面暂停它。
以协作模式运行.NET方法,生成的本机代码依赖于协作模式非抢占保证,以最有效地操作对象内存(GC堆等)。 如果您在外部并且“残酷地”在其执行中的任意点暂停协作GC线程,则可能使对象内存或其他CLR内部处于可能不适合正确的垃圾收集周期或其他CLR操作的状态。但这在实践中从未发生过,因为这不是协作模式线程的暂停方式。
(显然存在一些极端情况,例如当协作模式线程完成其OS线程调度程序量程时,OS上下文将该核心切换到某个其他线程。由于该线程不再运行,因此它不会轮询yield标志,我不记得在这种情况下会发生什么 - CLR是否必须等到它被重新安排,测试标志和产量,或者它是否暂停线程然后检查其IP到看看它是否在安全的地方。任何人?)
我相信这在SSCLI(转子)内部描述。
有道理吗?
快乐的黑客攻击!