在此示例中了解CER的用途

时间:2011-10-20 09:50:47

标签: c# list cer

我正在阅读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删除一个项目太少。

鉴于此,我在本例中难以理解约束执行区的目的。

我对此的理解是正确的还是我错过了什么?

1 个答案:

答案 0 :(得分:1)

CERs的文档和实际行为与我观察到的完全不符。您描述的ThreadAbortExceptionInsert之间注入numAdded++的问题是我测试过的任何.NET Framework版本都无法实现的。这有两个可能的原因。

  • PrepareConstrainedRegions尽管文档说明了,但对try块有明显的影响。它将推迟某些中止注射;特别是当线程处于可警告状态时不会出现的那些。
  • 即使没有PrepareConstrainedRegions电话,中止仍然不会被注入该位置。根据SSCLI代码,将在向后跳转时注入中止以旋转while循环。

在回答我自己的相关question here然后尝试回答有关Thread.Abort实际如何运作here的问题时,我想到了其中一些。

点#2不合法。这是SSCLI的一个实现细节,可能不会延续到官方发行版(虽然我怀疑它确实如此)。此外,它忽略了在执行Insert期间在某个时刻注入中止的可能性。我认为Insert的关键位可能会在内部使用CER。

第一点可能是重要的一点,但这就引出了微软为什么没有记录它的问题,为什么你引用的文章也没有提到它。当然,文章的作者知道这个事实。否则,我也不明白所提供的代码是如何安全的。换句话说,它现在似乎只是偶然的安全。

如果我不得不猜测PrepareConstrainedRegions在幕后做了什么,我会说它在JIT引擎中设置一个标志,告诉它不要注入战略性放置的GC轮询钩子向后分支跳转CER try块内的代码。此GC轮询钩子通常会注入异步中止(除了与垃圾收集相关的主要目的)。