3

我正在阅读受约束的执行区域和其他勘误表 [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.

鉴于此,我很难理解此示例中受约束的执行区域的用途。

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

4

1 回答 1

1

根据我的观察,CER 的文档和实际行为并不完全匹配。您描述的问题在我测试过的任何 .NET Framework 版本ThreadAbortException之间被注入Insert并且numAdded++不可能。这有两个可能的原因。

  • PrepareConstrainedRegions确实,不管文档怎么说,对try块有明显的影响。它会延迟某些中止注射;特别是那些在线程处于警报状态时不来的。
  • 即使在没有PrepareConstrainedRegions调用的情况下,中止仍然不会被注入该位置。基于 SSCLI 代码,中止将在向后跳转时注入以旋转while循环。

我在这里回答我自己的相关问题时想出了其中的一些,然后尝试回答有关此处Thread.Abort实际工作方式的问题。

第 2 点不合法。这是 SSCLI 的一个实现细节,可能不会延续到官方发行版(尽管我怀疑它确实如此)。此外,它忽略了在执行Insert. 我想它的关键部分Insert可能会在内部使用 CER。

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

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

于 2013-09-26T19:57:31.067 回答