【发布时间】:2010-11-09 05:24:18
【问题描述】:
除非应用[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)],否则任何人都可以创建一个简短的示例吗?
我刚刚浏览了这个sample on MSDN,即使我注释掉了 ReliabilityContract 属性,我也无法让它崩溃。最后似乎总是被调用。
【问题讨论】:
标签: c# .net concurrency cer
除非应用[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)],否则任何人都可以创建一个简短的示例吗?
我刚刚浏览了这个sample on MSDN,即使我注释掉了 ReliabilityContract 属性,我也无法让它崩溃。最后似乎总是被调用。
【问题讨论】:
标签: c# .net concurrency cer
虽然我没有具体的例子给你,但我认为你错过了在保证成功的方法中尝试 try..finally 的意义。说方法总是成功的意思是,在执行过程中发生什么(异常),将采取措施确保方法返回时正在访问的数据处于有效状态。如果没有 try..finally,您将无法确保任何事情,并且可能意味着您想要发生的操作只有一半会发生。因此,Cer.Success 实际上并不能保证成功,它只是表明您作为开发人员正在保证成功。
查看此页面,了解 Success 和 MayFail 状态之间的差异,因为它与 Array.CopyTo 方法有关:http://weblogs.asp.net/justin_rogers/archive/2004/10/05/238275.aspx
【讨论】:
CER 属性是文档的手段。它们确实会影响 CLR 在某些情况下执行代码的方式,但我相信它们(或缺少它们)永远不会在当前版本的 .NET 中导致错误。
它们大多是“保留以备将来使用”。
【讨论】:
您是否在调试器下运行 MSDN 示例?我认为当您在调试器中执行时,CER 不可能起作用,因为无论如何调试器本身都会改变执行的性质。
如果您在优化发布模式下构建和运行应用程序,您应该能够看到它失败。
【讨论】:
此功能的主要驱动力是支持 SQL Server 将 CLR 集成到 SQL Server 2005 中的严格要求。可能是为了让其他人可以使用并且可能出于法律原因,这种深度集成已作为托管 API 发布,但技术要求是SQL 服务器。请记住,在 SQL Server 中,MTBF 以月而不是小时为单位衡量,并且由于发生未处理的异常而重新启动进程是完全不可接受的。
这个MSDN Magazine article 可能是我见过的描述受约束的执行环境所针对的技术要求的最好的一个。
ReliabilityContract 用于装饰您的方法,以指示它们如何根据潜在的异步异常(ThreadAbortException、OutOfMemoryException、StackOverflowException)进行操作。受约束的执行区域定义为 try 块的 catch 或 finally(或故障)部分,紧接在调用 System.Runtime.CompilerServices.RuntimeServices.PrepareConstrainedRegions() 之前。
System.Runtime.CompilerServices.RuntimeServices.PrepareConstrainedRegions();
try
{
// this is not constrained
}
catch (Exception e)
{
// this IS a CER
}
finally
{
// this IS ALSO a CER
}
当在 CER 中使用 ReliabilityContract 方法时,会发生两件事。该方法将由 JIT 预先准备好,因此它不会在第一次执行时调用 JIT 编译器,这可能会尝试使用内存本身并导致它自己的异常。此外,在 CER 内部时,运行时承诺不会抛出 ThreadAbort 异常,并且会等到 CER 完成后才抛出异常。
回到你的问题;我仍在尝试提出一个简单的代码示例来直接回答您的问题。您可能已经猜到了,鉴于问题的异步性质,最简单的示例将需要大量代码,并且很可能是 SQLCLR 代码,因为这是使用 CER 获得最大收益的环境。
【讨论】:
SafeHandles 以确保它们已关闭。这包括导致 OS SafeHandle(GDI+、文件等)的任何 P/Invoke。如果您开始在 Windows 中泄漏句柄,您很快就会遇到麻烦。
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
class Program {
static bool cerWorked;
static void Main( string[] args ) {
try {
cerWorked = true;
MyFn();
}
catch( OutOfMemoryException ) {
Console.WriteLine( cerWorked );
}
Console.ReadLine();
}
unsafe struct Big {
public fixed byte Bytes[int.MaxValue];
}
//results depends on the existance of this attribute
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
unsafe static void StackOverflow() {
Big big;
big.Bytes[ int.MaxValue - 1 ] = 1;
}
static void MyFn() {
RuntimeHelpers.PrepareConstrainedRegions();
try {
cerWorked = false;
}
finally {
StackOverflow();
}
}
}
当MyFn 被jitted 时,它会尝试从finally 块中创建一个ConstrainedRegion。
如果没有ReliabilityContract,,则无法形成正确的ConstrainedRegion,因此会发出常规代码。调用Stackoverflow(在try块执行后)抛出堆栈溢出异常。
在ReliabilityContract 的情况下,可以形成ConstrainedRegion,并且可以将finally 块中的方法的堆栈要求提升到MyFn。现在调用 MyFn 时会引发堆栈溢出异常(在执行 try 块之前)。
【讨论】:
PrepareConstrainedRegions (afaik) 的限制。另请参阅 Richter 的 CLR 书籍:books.google.nl/…