我正在阅读Constrained Execution Regions and other errata [Brian Grunkemeyer]以尝试理解受约束的执行区域,但是我在理解以下示例时遇到了一些问题:
RuntimeHelpers.PrepareConstrainedRegions();
try {
// Prepare my backout code
MethodInfo m = _list.GetType().GetMethod("RemoveAt", new Type[] { typeof(int) });
RuntimeHelpers.PrepareMethod(m.MethodHandle);
IEnumerator en = c.GetEnumerator();
while(en.MoveNext()) {
_list.Insert(index++, en.Current);
// Assuming that these lines aren't reordered.
numAdded++;
}
_version++;
}
catch(Exception) {
// Reliable backout code
while(numAdded > 0) {
_list.RemoveAt(index--);
numAdded--;
}
throw;
}
我的理解是try
块不约束,只有finally和catch块受到约束。这意味着在try
块期间可以随时抛出异步异常(例如ThreadAbortException),特别是它可以在numAdded++
之前但在_list.Insert
之后抛出。在这种情况下,撤销代码会从_list
删除一个项目太少。
鉴于此,我在本例中难以理解约束执行区的目的。
我对此的理解是正确的还是我错过了什么?
答案 0 :(得分:1)
CERs的文档和实际行为与我观察到的完全不符。您描述的ThreadAbortException
和Insert
之间注入numAdded++
的问题是我测试过的任何.NET Framework版本都无法实现的。这有两个可能的原因。
PrepareConstrainedRegions
尽管文档说明了,但对try
块有明显的影响。它将推迟某些中止注射;特别是当线程处于可警告状态时不会出现的那些。PrepareConstrainedRegions
电话,中止仍然不会被注入该位置。根据SSCLI代码,将在向后跳转时注入中止以旋转while
循环。在回答我自己的相关question here然后尝试回答有关Thread.Abort
实际如何运作here的问题时,我想到了其中一些。
Insert
期间在某个时刻注入中止的可能性。我认为Insert
的关键位可能会在内部使用CER。
第一点可能是重要的一点,但这就引出了微软为什么没有记录它的问题,为什么你引用的文章也没有提到它。当然,文章的作者知道这个事实。否则,我也不明白所提供的代码是如何安全的。换句话说,它现在似乎只是偶然的安全。
如果我不得不猜测PrepareConstrainedRegions
在幕后做了什么,我会说它在JIT引擎中设置一个标志,告诉它不要注入战略性放置的GC轮询钩子向后分支跳转CER try
块内的代码。此GC轮询钩子通常会注入异步中止(除了与垃圾收集相关的主要目的)。