- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在玩弄 Constrained Execution Regions今晚更好地完善我对细节的理解。我以前偶尔使用过它们,但在那些情况下,我大多严格遵守既定模式。不管怎样,我注意到了一些我无法解释的奇怪现象。
考虑以下代码。请注意,我以 .NET 4.5 为目标,并使用未附加调试器的发布版本对其进行了测试。
public class Program
{
public static void Main(string[] args)
{
bool toggle = false;
bool didfinally = false;
var thread = new Thread(
() =>
{
Console.WriteLine("running");
RuntimeHelpers.PrepareConstrainedRegions();
try
{
while (true)
{
toggle = !toggle;
}
}
finally
{
didfinally = true;
}
});
thread.Start();
Console.WriteLine("sleeping");
Thread.Sleep(1000);
Console.WriteLine("aborting");
thread.Abort();
Console.WriteLine("aborted");
thread.Join();
Console.WriteLine("joined");
Console.WriteLine("didfinally=" + didfinally);
Console.Read();
}
}
你认为这个程序的输出会是什么?
在您猜测之前阅读文档。我在下面包括了相关部分。
A constrained execution region (CER) is part of a mechanism for authoring reliable managed code. A CER defines an area in which the common language runtime (CLR) is constrained from throwing out-of-band exceptions that would prevent the code in the area from executing in its entirety. Within that region, user code is constrained from executing code that would result in the throwing of out-of-band exceptions. The PrepareConstrainedRegions method must immediately precede a try block and marks catch, finally, and fault blocks as constrained execution regions. Once marked as a constrained region, code must only call other code with strong reliability contracts, and code should not allocate or make virtual calls to unprepared or unreliable methods unless the code is prepared to handle failures. The CLR delays thread aborts for code that is executing in a CER.
和
The reliability try/catch/finally is an exception handling mechanism with the same level of predictability guarantees as the unmanaged version. The catch/finally block is the CER. Methods in the block require advance preparation and must be noninterruptible.
我现在特别关心的是防止线程中止。有两种类型:通过 Thread.Abort
的正常类型,以及 CLR 主机可以对您进行所有中世纪操作并强制中止的类型。 finally
block 已经在某种程度上防止了 Thread.Abort
。然后,如果您将 finally
block 声明为 CER,那么您也会获得针对 CLR 主机中止的额外保护……至少我认为这是理论。
所以根据我所知道的,我猜到了#1。它应该打印 didfinally=True。 ThreadAbortException
被注入(inject),而代码仍在 try
block 中,然后 CLR 允许 finally
block 按预期运行,即使没有CER 对吗?
嗯,这不是我得到的结果。我得到了一个完全出乎意料的结果。 #1 或#2 都没有发生在我身上。相反,我的程序卡在 Thread.Abort
。这是我观察到的。
PrepareConstrainedRegions
的存在延迟了 try
block 内的线程中止。PrepareConstrainedRegions
的缺失允许它们在 try
block 中。所以百万美元的问题是为什么?文档在我能看到的任何地方都没有提到这种行为。事实上,我正在阅读的大部分内容实际上是在建议您将关键的不可中断代码放在 finally
block 中,专门用于防止线程中止。
也许,PrepareConstrainedRegions
除了 finally
block 之外,还延迟了 try
block 中的正常中止。但是 CLR 主机中止仅在 CER 的 finally
block 中延迟?谁能更清楚地说明这一点?
最佳答案
[接评论]
我会将我的回答分为两部分:CER 和处理 ThreadAbortException。
我不认为 CER 最初旨在帮助解决线程中止问题;这些不是你要找的机器人。有可能我也误解了问题的陈述,这些东西往往会变得很沉重,但我发现文档中的关键短语(诚然,其中一个实际上与我提到的不同)是:
代码不能导致带外异常
和
用户代码使用可靠的 try/catch/finally 创建不可中断区域,*包含一个空的 try/catch block *,前面是 PrepareConstrainedRegions 方法调用
尽管没有直接在受约束的代码中受到启发,但线程中止是一种带外异常。受限区域仅保证,一旦 finally 执行,只要它遵守其 promise 的约束,它就不会因托管运行时操作而中断,否则不会中断非托管 finally block 。线程中止会中断非托管代码,就像它们会中断托管代码一样,但如果没有受限区域, 会有一些保证,并且可能还有针对您正在寻找的行为的不同推荐模式。我怀疑这主要是作为防止垃圾收集线程挂起的障碍(如果我不得不猜测的话,可能是通过在该区域的持续时间内将线程从抢占式垃圾收集模式切换出来)。我可以想象将它与弱引用、等待句柄和其他低级别管理例程结合使用。
至于意外行为,我的想法是你没有满足你通过声明约束区域 promise 的契约(Contract),所以结果没有记录,应该被认为是不可预测的。 Thread Abort 会在 try 中延迟,这看起来确实很奇怪,但我认为这是无意使用的副作用,这只值得进一步探索运行时的学术理解(一类知识是易变的,因为不能保证 future 的更新可能会改变这种行为)。
现在,我不确定以非预期方式使用上述副作用的程度有多大,但如果我们退出使用力来影响我们的控制 body 并让事情按照它们的方式运行通常情况下,我们确实会得到一些保证:
有了这个,这里有一个技术示例意味着在需要中止弹性的情况下使用。我在一个示例中混合了多种技术,这些技术没有必要同时使用(通常您不会)只是为了根据您的需要提供一些选项示例。
bool shouldRun = true;
object someDataForAnalysis = null;
try {
while (shouldRun) {
begin:
int step = 0;
try {
Interlocked.Increment(ref step);
step1:
someDataForAnalysis = null;
Console.WriteLine("test");
Interlocked.Increment(ref step);
step2:
// this does not *guarantee* that a ThreadAbortException will not be thrown,
// but it at least provides a hint to the host, which may defer abortion or
// terminate the AppDomain instead of just the thread (or whatever else it wants)
Thread.BeginCriticalRegion();
try {
// allocate unmanaged memory
// call unmanaged function on memory
// collect results
someDataForAnalysis = new object();
} finally {
// deallocate unmanaged memory
Thread.EndCriticalRegion();
}
Interlocked.Increment(ref step);
step3:
// perform analysis
Console.WriteLine(someDataForAnalysis.ToString());
} catch (ThreadAbortException) {
// not as easy to do correctly; a little bit messy; use of the cursed GOTO (AAAHHHHHHH!!!! ;p)
Thread.ResetAbort();
// this is optional, but generally you should prefer to exit the thread cleanly after finishing
// the work that was essential to avoid interuption. The code trying to abort this thread may be
// trying to join it, awaiting its completion, which will block forever if this thread doesn't exit
shouldRun = false;
switch (step) {
case 1:
goto step1;
break;
case 2:
goto step2;
break;
case 3:
goto step3;
break;
default:
goto begin;
break;
}
}
}
} catch (ThreadAbortException ex) {
// preferable approach when operations are repeatable, although to some extent, if the
// operations aren't volatile, you should not forcibly continue indefinite execution
// on a thread requested to be aborted; generally this approach should only be used for
// necessarily atomic operations.
Thread.ResetAbort();
goto begin;
}
我不是 CER 方面的专家,所以如果我有任何误解,请告诉我。我希望这会有所帮助:)
关于c# - 可以解释 PrepareConstrainedRegions 和 Thread.Abort 的这种意外行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18501678/
我想创建一个基于 jQuery 的非常简单的 html 编辑器(不是所见即所得)。 我的问题是如何制作 textarea或 div可能 在上面写一些文字 然后样式即标签(例如 some stuff 将
根据文档 isset 条款“测试此项目中是否已设置给定属性”。我不明白设置属性时 isset 返回 true 还是 false 在下面的代码片段中,当 env.JAVA_HOME 未设置时,java.
我正在尝试取消映射 o这是执行 :only 的默认命令( :help :only ),所以我尝试的第一件事是: nmap o 这种作品,除非我按 ,等待超过timeoutlen ms 然后按 o
我有以下型号: class MetaData(models.Model): created_at = models.DateTimeField(auto_now_add=True, auto_
下面列出了两行代码。两者对日期和时间的期望相同,但只有一个有效。我正在使用 R 3.1。 以下不起作用: DateTime2=strftime("08/13/2010 05:26:24.350", f
我有一个关于 C 代码的问题。 #include void foo(void){ int a; printf("%d\n",a); } void bar(void){
如果文件大小 > 8k,为什么读取的最后一个字节 = 0? private static final int GAP_SIZE = 8 * 1024; public static void main(
我有一个命令 Get-Testdata从不同来源检索测试数据并将这些数据存储到 PSObject以不同的值作为属性。然后将对象总数存储为数组,以便于操作、排序、计算等。 我的问题是我希望能够将这些数据
我正在使用 epoll 将大消息写入使用 HTTP 协议(protocol)的服务器。 fds 都设置为非阻塞,我正在使用边缘触发事件。我知道对于 EPOLLIN,我需要循环读取 fd,直到返回 EA
这对我来说听起来很奇怪: $test_1 = 'string'; $test_2 = '0'; var_dump(intval($test_1)); // Output: int 0 var_dump
这个问题在这里已经有了答案: Java: Integer equals vs. == (7 个回答) 7年前关闭。 请您解释以下行为。 public class EqAndRef { publ
Drupal 的行为到底是什么? 它为模块开发人员提供什么类型的服务层? 它映射到 jQuery.ready 的关系类型是什么? 最佳答案 长版:Drupal.behaviors 不仅仅是 jQuer
以下代码: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ for (int i=0
人们可以将项目添加到数据库中。我让他们选择在此时添加它,或手动选择日期。 因此我得到了这个 HTML 结构。 (请注意,我将日期和时间选择器妥协为只有一行文本) Selec
创建了一个数据框: simpleDF is.na(simpleDF$vals) [1] TRUE TRUE FALSE > is.nan(simpleDF$vals) [1] FALSE TRU
我有一个大的 docker 镜像 A,我创建了一个新的 Dockerfile FROM A RUN rm /big-folder 我尝试使用以下方法构建图像: docker build --squas
我想知道以下情况下 JVM 的行为是什么: JVM 最小堆大小 = 500MB JVM 最大堆大小 = 2GB 操作系统有 1GB 内存 JVM启动后,程序运行一段时间后,使用内存超过1GB。我想知道
我们正在使用 spikeearrest 策略,但我们不了解其工作原理。峰值逮捕配置如下: 5pm 阅读文档,我们了解到,如果我们在一分钟内调用此流超过 5 次,则该策略将在第 5 次之后
我正在使用 cURL 发送 POST 请求: curl http://tarvos.local:8080/partial_Users/2 -d '{currentPage : 1, firstID :
我的表中有 6442670 条记录,我正在使用以下命令获取它们jdbctemplate 使用行号一次 1000000 个。以下是查询 select * from (select rowNum rn
我是一名优秀的程序员,十分优秀!