我今晚在玩Constrained Execution Regions,以更好地理解我对细节的理解。我之前曾使用过它们,但在那些情况下,我大多数都严格遵守既定模式。无论如何,我注意到了一些我不能解释的奇特的东西。可以解释PrepareConstrainedRegions和Thread.Abort的这种意外行为吗?
考虑下面的代码。请注意,我的目标是.NET 4.5,并且在没有附加调试器的情况下使用Release版本进行测试。
public class Program
{
public static void Main(string[] args)
{
bool toggle = false;
bool didfinally = false;
var thread = new Thread(
() =>
{
Console.WriteLine("running");
RuntimeHelpers.PrepareConstrainedRegions();
try
{
while (true)
{
toggle = !toggle;
}
}
finally
{
didfinally = true;
}
});
thread.Start();
Console.WriteLine("sleeping");
Thread.Sleep(1000);
Console.WriteLine("aborting");
thread.Abort();
Console.WriteLine("aborted");
thread.Join();
Console.WriteLine("joined");
Console.WriteLine("didfinally=" + didfinally);
Console.Read();
}
}
你认为这个程序的输出是什么?
- didfinally =真
- didfinally =假
之前你猜阅读文档。我在下面列出了相关部分。
约束执行区域(CER)是编写可靠托管代码的机制的一部分。甲CER限定其中 公共语言运行库(CLR)从抛出带外 例外将防止在该地区的代码从 其全部执行限制的区域。内的区域中,用户代码从 执行代码将导致出带外 例外的投掷限制。 的PrepareConstrainedRegions方法必须立即 先于try块和标记赶上,最后,与故障块作为 约束的执行区域。一旦标记为约束区域, 代码只能调用具有强可靠性合同的其他代码,并且 代码不应分配或虚拟调用不可靠的方法或不可靠的方法,除非代码准备处理失败。 CLR延迟在CER中执行的代码的线程中止。
和
可靠性的try/catch /最后是一个异常处理机制 与同级别的可预测性担保作为非托管 版本。 catch/finally块是CER。块 中的方法需要提前准备,并且必须是不可中断的。
我特别关注现在的问题是防范线程中止。有两种:通过Thread.Abort
进行的正常变化,然后是CLR主机可以对你全部中世纪进行强制中止的那种。 finally
块在某种程度上已经被保护而不受Thread.Abort
的影响。然后,如果您将finally
块声明为CER,那么您可以从CLR主机中止获得额外保护,至少我认为这是理论。
因此,基于我在想什么,我知道我猜#1。它应该打印didfinally = True。当代码仍在try
块中时,ThreadAbortException
被注入,然后CLR允许finally
块按预期运行,即使没有CER权限也是如此?
嗯,这不是我得到的结果。我得到了一个完全意外的结果。 #1或#2都不适合我。相反,我的程序挂在Thread.Abort
。这是我观察到的。
PrepareConstrainedRegions
的存在延迟线程在try
块内部中止。PrepareConstrainedRegions
的缺席允许他们在try
块。
那么百万美元的问题是为什么呢?文档没有提到我能看到的任何地方的这种行为。实际上,我正在阅读的大部分内容实际上都是暗示您在finally
区块中放置了不可中断的关键代码,以防止线程中止。
也许,PrepareConstrainedRegions
延迟正常中止在除了finally
块try
块。但是CLR主机异常终止只在CER的finally
块中延迟?任何人都可以提供更多的清晰度?
你说得很好。我认为我的大部分困惑都来自文档,暗示'try'块不是CER的一部分。那么为什么我们应该期待带外的异常在执行'try'块时被延迟。通常你会在'PrepareConstrainedRegions'之后立即看到'try'块。不过,在这种情况下,我喜欢你关于“未定义的行为”的观点。我绝对可以接受这个理由。我将继续并接受答案。 –
是的,我实际上认为我明白发生了两次事情,然后才意识到整个情况都在描述的背景之外。 – TheXenocide