了解本示例中 CER 的用途

发布于 2024-12-11 11:56:10 字数 1070 浏览 0 评论 0原文

我正在阅读 约束执行区域和其他勘误表 [Brian Grunmeeyer] 试图理解约束执行区域,但是我在理解以下示例时遇到了一些问题:

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之后抛出。插入。在这种情况下,撤销代码将从 _list 中删除一项太少的项目。

鉴于此,我正在努力理解本示例中约束执行区域的用途。

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

I'm reading through Constrained Execution Regions and other errata [Brian Grunkemeyer] in an attempt to understand constrained execution regions, however I'm having some problems understanding the following sample:

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;
}

My understanding is that the try block is not constrained, only the finally and catch blocks are constrained. This means that during the try block an asynchronous exception (e.g. ThreadAbortException) can be thrown at any time, in particular it could be thrown before numAdded++ but after _list.Insert. In this case the backout code would remove one item too few from _list.

Given this I'm struggling to understand the purpose of the constrained execution region in this example.

Is my understanding of this correct or have I missed something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

许你一世情深 2024-12-18 11:56:10

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

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

我在回答我自己的相关此处的问题,然后尝试回答有关Thread如何工作的问题时,想出了一些办法.Abort实际上可以在这里工作。

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

第 1 点可能是最重要的,但这引出了一个问题:为什么 Microsoft 没有记录它以及为什么您引用的文章也没有提及它。这篇文章的作者肯定知道这个事实。否则,我也不明白所提供的代码如何可能是安全的。换句话说,目前看来安全只是偶然的。

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

The documentation and the actual behavior of CERs do not match exactly based on what I observe. The issue you describe where a ThreadAbortException gets injected between Insert and numAdded++ is not possible with any of the .NET Framework versions I have tested. There are two possible reasons for this.

  • PrepareConstrainedRegions does, despite what the documentation says, have an observable effect on the try block. It will delay certain abort injections; specifically those that do not come while the thread is in an alertable state.
  • Even in the absence of the PrepareConstrainedRegions call the abort still will not get injected into that location. Based on the SSCLI code the abort will be injected at the backward jump to spin the while loop.

I figured some of this out while answering my own related question here and then attempting to answer a question about how Thread.Abort actually works here.

Point #2 is not legit. It is an implementation detail of the SSCLI that may not carry over to the official distributions (though I suspect it actually does). Furthermore, it ignores the possibility of having the abort injected at some point during the execution of Insert. I suppose it is possible that the crucial bits of Insert could use a CER internally though.

Point #1 may be the one that matters, but that begs the questions why did Microsoft not document it and why did the article you cited not mention it either. Surely the author of the article knew of this fact. Otherwise, I too am not understanding how the code presented could possibly be safe. In other words, it seems safe only by accident right now.

If I had to take a guess as to what PrepareConstrainedRegions is doing behind the scenes I would say that it sets a flag in the JIT engine that tells it not to inject the GC poll hook that gets placed strategically at backward branch jumps for code inside a CER try block. This GC poll hook is where the asynchronous abort would typically be injected (in addition to its main purpose related to garbage collection).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文