我正在通读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
中删除太少的一项。鉴于此,在本示例中,我努力理解受约束执行区域的目的。
我对此是否正确理解还是错过了什么?
最佳答案
根据我的观察,CER的文档和实际行为并不完全匹配。您描述的问题在我测试过的任何.NET Framework版本中都不可能在ThreadAbortException
和Insert
之间注入numAdded++
。可能有两个原因。
尽管文档中有说明,PrepareConstrainedRegions
确实对try
块具有可观察到的影响。这将延迟某些中止注射。特别是那些线程处于警报状态时不会出现的事件。
即使没有PrepareConstrainedRegions
调用,异常终止仍然不会注入该位置。根据SSCLI代码,异常终止将在向后跳转时注入,以旋转while
循环。
我在回答自己相关的question here并尝试回答有关Thread.Abort
实际工作方式here的问题时想出了一些办法。
第二点是不合法的。这是SSCLI的实现细节,可能不会延续到官方发行版中(尽管我怀疑确实如此)。此外,它忽略了在执行Insert
期间的某个时候注入异常终止的可能性。我想Insert
的关键部分可能会在内部使用CER。
要点1可能很重要,但这引出了一个问题,即Microsoft为什么不记录它,为什么您引用的文章也没有提到它。当然,本文的作者知道这一事实。否则,我也不太理解所提供的代码可能是安全的。换句话说,现在看来只是偶然的安全。
如果我不得不猜测PrepareConstrainedRegions
在后台执行的操作,我会说它在JIT引擎中设置了一个标志,告诉它不要注入将策略性地放置在向后分支跳转处的代码的GC轮询挂钩。在CER try
块中。该GC轮询钩子通常是在其中注入异步异常终止的(除了它与垃圾回收有关的主要目的之外)。
关于c# - 在此示例中了解CER的目的,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7834110/