我正在通读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版本中都不可能在ThreadAbortExceptionInsert之间注入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/

10-10 13:47