我正在尝试运行涉及线程和关键区域的示例代码(非常基本的代码)。
这是我的代码:
public static void DoCriticalWork(object o)
{
SomeClass instance = o as SomeClass;
Thread.BeginCriticalRegion();
instance.IsValid = true;
Thread.Sleep(2);
instance.IsComplete = true;
Thread.EndCriticalRegion();
instance.Print();
}
我称之为:
private static void CriticalHandled()
{
SomeClass instance = new SomeClass();
ParameterizedThreadStart operation = new ParameterizedThreadStart(CriticalRegion.DoCriticalWork);
Thread t = new Thread(operation);
Console.WriteLine("Start thread");
t.Start(instance);
Thread.Sleep(1);
Console.WriteLine("Abort thread");
t.Abort();
Console.WriteLine("In main");
instance.Print();
}
然而,我得到的输出是:
**
Start thread
Abort thread
In main
IsValid: True
IsComplete: False
**
由于定义了关键区域,因此IsComplete应该为true而不是false。
有人可以解释为什么它不起作用吗?
以下是SomeClass供参考:
public class SomeClass
{
private bool _isValid;
public bool IsValid
{
get { return _isValid; }
set { _isValid = value; }
}
private bool _isComplete;
public bool IsComplete
{
get { return _isComplete; }
set { _isComplete = value; }
}
public void Print()
{
Console.WriteLine("IsValid: {0}", IsValid);
Console.WriteLine("IsComplete: {0}", IsComplete);
Console.WriteLine();
}
}
修改
从MCTS注释: 关键区域背后的想法是提供必须执行的代码区域,就像它是单行一样。任何在线程处于关键区域内时中止线程的尝试都必须等到关键区域完成之后。此时,线程将被中止,抛出ThreadAbortException。具有和不具有关键区域的线程之间的差异如下图所示:
Critical Region http://www.freeimagehosting.net/uploads/9dd3bb5445.gif
答案 0 :(得分:7)
Thread.BeginCriticalRegion不会阻止线程被中止。我相信它用于通知运行时如果线程在关键部分中止,则继续运行应用程序/ AppDomain不一定安全。
MSDN文档有更完整的解释:http://msdn.microsoft.com/en-us/library/system.threading.thread.begincriticalregion.aspx
答案 1 :(得分:1)
这是一个睡眠时间问题。只是扩大两个睡眠之间的差距,你就会得到答案。
有两个线程:主线程和执行关键工作的线程。现在,当调用abort时,线程't'将立即中止,即使它尚未完成关键区域。
现在,因为你已经发送主线程休眠2ms并且线程t持续1ms,有时t将完成临界区,有时它不会。这就是为什么IsComplete的值有时是假的,有时是真的。
现在只需将主线程发送到睡眠状态100ms,您会发现IsComplete始终为true。 反之亦然,将线程“t”发送到睡眠状态100ms,你会发现IsComplete总是为假。
修改强>
来自MSDN
通知主机执行即将进入代码区域,其中线程中止或未处理的异常的影响可能会危及应用程序域中的其他任务。
例如,考虑一个尝试在持有锁时分配内存的任务。如果内存分配失败,中止当前任务是不够的以确保AppDomain的稳定性,因为域中可能有其他任务正在等待同一个锁。如果当前任务终止,则其他任务可能会死锁。
当关键区域发生故障时,主机可能决定卸载整个AppDomain,而不是承担在潜在不稳定状态下继续执行的风险。要通知主机您的代码正在进入关键区域,请调用BeginCriticalRegion。当执行返回到非关键的代码区域时调用EndCriticalRegion。
来自CLR Inside Out: Writing Reliable Code
国家腐败 国家腐败可能涉及三个桶。第一种是本地状态,它包括仅由特定线程使用的局部变量和堆对象。第二种是共享状态,它包括AppDomain中各个线程之间共享的任何内容,例如存储在静态变量中的对象。缓存通常属于此类别。第三个是整个流程范围,机器范围内,跨机器共享状态文件,套接字,共享内存和分布式锁定管理器都属于这个阵营。
异步异常可能损坏的状态量是线程当前正在修改的最大状态量。如果一个线程分配了一些临时对象并且没有将它们暴露给其他线程,那么只有那些临时对象可能被破坏。 但是如果线程正在写入共享状态,则该共享资源可能已损坏,而其他线程可能会遇到此损坏状态。你不能让这种情况发生。在这种情况下,您将中止AppDomain中的所有其他线程,然后卸载AppDomain 。通过这种方式,异步异常会升级到AppDomain,从而导致它卸载并确保丢弃任何可能已损坏的状态。给定像数据库这样的事务存储,此AppDomain回收可为本地和共享状态的损坏提供弹性。
关键区域允许您处理某些代码可能损坏其他应用程序域并对系统造成无法修复的损坏的情况。
答案 2 :(得分:0)
一个好的解决方案是使用
封装来自DoCriticalWork()
的代码
try { ... } catch(ThreadAbortedException) {...}
你应该按照自己的意愿行事(也许设置IsComplete = true
?)
您可以阅读有关ThreadAbortException的更多信息,并确保针对此案例检查Thread.ResetAbort
和finally
阻止使用情况。
正如 Andy 提到并引用Thread.BeginCriticalRegion:
通知主机执行即将进入代码区域,其中线程中止或未处理异常的影响可能会危及应用程序域中的其他任务。