了解本示例中 CER 的用途
我正在阅读 约束执行区域和其他勘误表 [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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据我的观察,文档和 CER 的实际行为并不完全匹配。您所描述的在
Insert
和numAdded++
之间注入ThreadAbortException
的问题对于我测试过的任何 .NET Framework 版本都是不可能的。造成这种情况的原因有两个可能。PrepareConstrainedRegions
确实对try
块有明显的影响。它会延迟某些中止注射;特别是那些在线程处于可警报状态时不会出现的线程。PrepareConstrainedRegions
调用,中止仍然不会被注入到该位置。基于 SSCLI 代码,将在向后跳转处注入中止以旋转while
循环。我在回答我自己的相关此处的问题,然后尝试回答有关
Thread如何工作的问题时,想出了一些办法.Abort
实际上可以在这里工作。第 2 点不合法。这是 SSCLI 的实现细节,可能不会延续到官方发行版(尽管我怀疑它确实如此)。此外,它忽略了在执行
Insert
期间的某个时刻注入中止的可能性。我认为Insert
的关键部分可能会在内部使用 CER。第 1 点可能是最重要的,但这引出了一个问题:为什么 Microsoft 没有记录它以及为什么您引用的文章也没有提及它。这篇文章的作者肯定知道这个事实。否则,我也不明白所提供的代码如何可能是安全的。换句话说,目前看来安全只是偶然的。
如果我不得不猜测
PrepareConstrainedRegions
在幕后做了什么,我会说它在 JIT 引擎中设置了一个标志,告诉它不要注入策略性放置的 GC poll 钩子CERtry
块内的代码向后分支跳转。此 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 betweenInsert
andnumAdded++
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 thetry
block. It will delay certain abort injections; specifically those that do not come while the thread is in an alertable state.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 thewhile
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 ofInsert
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 CERtry
block. This GC poll hook is where the asynchronous abort would typically be injected (in addition to its main purpose related to garbage collection).