【问题标题】:Understanding the purpose of CERs in this example了解本示例中 CER 的用途
【发布时间】:2013-09-28 00:46:51
【问题描述】:

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

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

我对此的理解是正确的还是我遗漏了什么?

【问题讨论】:

  • 这里肯定有问题。

标签: c# list cer


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2013-03-26
    • 2013-04-13
    • 1970-01-01
    相关资源
    最近更新 更多