
























传统的失败处理策略遵循如下模式:
上述所有方法都不能很容易的用于并发、异步执行,特别是前两种方法根本就不可能用于异步编程。方法在任意的上下文中执行,可能和调用者并行执行。除非有阻塞操作来收集异步操作的结果,阻塞一个在调用者上下文中的线程,失败或者成功都不能很容易的被检测。CLR中的异步编程模型使用Begin/End调用,引入了附加的复杂性,因为附加调用和无论操作结果如何都会被调用到的回调中的异常处理中都需要做失败处理。启动异步操作的代码不是进行失败处理的地方使得代码难以阅读。
CCR分两步解决失败处理的问题:
Causality是指可以跨多个执行上下文的一串操作,分支或者连接,创建一颗只有一个根的执行逻辑树。这个逻辑分组称为因果关系上下文,隐式的从一个消息的发送者传递到接收者。
Causalities是一种结构化异常机制在多线程环境的扩展。它们允许嵌套,但是依然处理多个并发的一场和与其他的causalities合并(例如因为连接(joins)操作)。
例22.
void SimpleCausalityExample()
{
Port<Exception> exceptionPort = new Port<Exception>();// create a causality using the port instance
Causality exampleCausality = new Causality("root cause", exceptionPort);// add causality to current thread
Dispatcher.AddCausality(exampleCausality);// any unhandled exception from this point on, in this method or
// any delegate that executes due to messages from this method,
// will be posted on exceptionPort.
Port<int> portInt = new Port<int>();
Arbiter.Activate(_taskQueue,
Arbiter.Receive(false, portInt, IntHandler)
);// causalities flow when items are posted or Tasks are scheduled
portInt.Post(0);// activate a handler on the exceptionPort
// This is the failure handler for the causality
Arbiter.Activate(_taskQueue,
Arbiter.Receive(false, exceptionPort,
delegate(Exception ex)
{
// deal with failure here
Console.WriteLine(ex);
})
);
}void IntHandler(int i)
{
// print active causalities
foreach (Causality c in Dispatcher.ActiveCausalities)
{
Console.WriteLine(c.Name);
}// expect DivideByZeroException that CCR will redirect to the causality
int k = 10 / i;
}
在上面的例子中我们演示了一个简单的场景,causalities帮助处理跨多个异步操作的错误。代码的关键步骤如下:
例23.
public void NestedCausalityExample()
{
Port<Exception> exceptionPort = new Port<Exception>();
Causality parentCausality = new Causality(
"Parent",
exceptionPort);
Dispatcher.AddCausality(parentCausality);
Port
<int> portInt = new Port<int>();
Arbiter.Activate(_taskQueue,
Arbiter.Receive(
例子的输出:
Before child is added: Parent After child is added: Child Child:System.InvalidOperationException: Testing causality support. Child causality will catch this one at Examples.Examples.IntHandlerNestingLevelOne(Int32 i)
in C:\mri\main\CCR\testsrc\UnitTests\ccruserguideexamples.cs:line 571 at Microsoft.Ccr.Core.Task`1.Execute()
in C:\mri\main\CCR\src\Core\Templates\GeneratedFiles\Task\Task01.cs:line 301 at Microsoft.Ccr.Core.TaskExecutionWorker.ExecuteTaskHelper(ITask currentTask)
in C:\mri\main\CCR\src\Core\scheduler_roundrobin.cs:line 1476 at Microsoft.Ccr.Core.TaskExecutionWorker.ExecuteTask(ITask& currentTask, DispatcherQueue p)
in C:\mri\main\CCR\src\Core\scheduler_roundrobin.cs:line 1376 at Microsoft.Ccr.Core.TaskExecutionWorker.ExecutionLoop()
in C:\mri\main\CCR\src\Core\scheduler_roundrobin.cs:line 1307
在上面的例子中,我们演示了一个嵌套的异步序列:
CCR的因果关系实现了一个独一无二的功能:它可以组合从两个不同的执行路径来的因果关系。类似于结构化异常,但是推广到并发的情况。因果关系可以嵌套,给程序员在内部外部因果关系中处理异常或者显式的投递到父因果关系中。
例24.
public void JoinedCausalityExample()
{
Port<int> intPort = new Port<int>();
Port<int> leftPort = new Port<int>();
Port<string> rightPort = new Port<string>();
Port
<Exception> leftExceptionPort = new Port<Exception>();Causality leftCausality
= new Causality("left", leftExceptionPort);
Arbiter.Activate(_taskQueue,
Arbiter.Receive(
例子的输出:
Left causality: System.InvalidOperationException: This exception will propagate to two peer causalities Right causality: System.InvalidOperationException: This exception will propagate to two peer causalities
为了可读性,上面的例子中大量使用了匿名方法来保持所有的逻辑都在一个方法中。这个例子演示了:
关键点是:当连接处理器(join handler)执行并且抛出异常,两个peer causalities被激活并且都独立的得到了投递到他们所负责的exception port上的异常。
重要:由于causalities使用常规的CCR ports来接收异常,你可以使用CCR协调原语来组合跨多个causalitites的异常处理。Joins,interleave和choice全都是合适的而且强大的方式来组合跨多个并发,多层异步操作的异常处理。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。