Task 编程中的异常处理

简介:

在 .Net 开发中, 使用 Task 、 Task<T> 进行异步编程是非常方便的, 但是在处理 Task 产生的异常时, 需要注意一个问题, 比如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
static  Task< int > TestAsync( int  a, int  b) {
    var  tcs = new  TaskCompletionSource< int >();
    Task.Factory.StartNew(() => {
       if  (a + b < 0) {
          tcs.TrySetException( new  InvalidOperationException( "a + b < 0" ));
       }
       else  {
          tcs.TrySetResult(a + b);
       }
    });
    return  tcs.Task;
}

当输入的两个参数之和小于 0 时, tcs 会设置一个 InvalidOperationException , 如果直接运行这段代码, 当这个函数返回的 Task 被 GC 回收时, 将会产生 AggregateException was unhandled 的异常, 运行代码如下:

1
2
3
4
5
6
7
8
9
10
static  void  Main( string [] args) {
 
    TestAsync(5, -10);
 
    Thread.Sleep(TimeSpan.FromMilliseconds(3000));
 
    GC.Collect();
 
    Console.WriteLine( "Completed." );
}

当程序运行结束时, 会产生下图所示的异常:

2012-07-05_130006

关键的是这段文字:

A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

没有在等待 Task 完成时捕获其异常, 也没有读取 Task 的 Exception 属性, 结果导致异常被终结线程重新抛出。 也就是说, Task 异常有两种处理方式:

1、 调用 Task 的 Wait 方法时使用 try-catch 捕获异常:

1
2
3
4
5
6
7
var  testTask = TestAsync(5, -10);
try  {
    testTask.Wait();
}
catch (Exception ex) {
    Console.WriteLine(ex);
}

2、 在 Task 的 ContinueWith 方法中读取 Task 的 Exception 属性:

1
2
3
4
5
6
7
8
9
var  testTask = TestAsync(5, -10);
testTask.ContinueWith(task => {
    if  (task.IsFaulted) {
       Console.WriteLine(task.Exception.GetBaseException());
    }
    else  {
       Console.WriteLine(task.Result);
    }
});

在 .Net 4.0 、 Sliverlight 5.0 、以及 MonoTouch 中均有类似的问题, 因此, 必须小心翼翼的处理 Task 产生的异常, 否则将会导致你的程序异常退出。

张志敏所有文章遵循创作共用版权协议,要求署名、非商业 、保持一致。在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处。

本博客已经迁移到 GitHub , 围观地址: http://beginor.github.io/

本文转自张志敏博客园博客,原文链接:http://www.cnblogs.com/beginor/archive/2012/07/05/2577692.html ,如需转载请自行联系原作者
相关文章
|
3月前
|
C# 开发者
深入理解C#中的`Task<T>`:异步编程的核心
【1月更文挑战第3天】本文旨在探讨C#中`Task<T>`的使用和理解,作为异步编程模式的核心组件。`Task<T>`允许开发者在不阻塞主线程的情况下执行异步操作,并返回一个指定类型`T`的结果。通过定义返回`Task<T>`的异步方法、使用`async`和`await`关键字、处理异常以及获取任务结果,开发者可以编写出高效且响应迅速的应用程序。此外,本文还介绍了如何配置任务以及实现任务的连续性和组合,为掌握C#中的异步编程提供了全面的指导。
|
12天前
|
监控 Java
解析Java线程池的异常处理机制
该内容是一个关于Java线程和线程池异常处理的总结。提到的关键点包括: 1. 引用了滑动验证页面和相关文章资源。 2. 区分了`execute`与`submit`在处理线程异常时的区别,`submit`可能会捕获并隐藏异常,而`execute`会直接抛出。 3. 提供了处理线程和线程池异常的建议,如使用try/catch直接捕获,或者自定义线程工厂和未捕获异常处理器。 4. 示例代码展示了如何通过设置`UncaughtExceptionHandler`来监控和处理线程中的异常。 请注意,由于字符限制,这里只提供了简要摘要,详细解释和代码示例请参考原文。
20 3
|
Java Go
一文搞懂Go语言错误处理【异常捕获、异常抛出】
一文搞懂Go语言错误处理【异常捕获、异常抛出】
288 0
一文搞懂Go语言错误处理【异常捕获、异常抛出】
|
11月前
异常处理finally你2个不知道的知识点
1.当try和catch中有return时,是否会跳过finally? 否。当执行到try和catch中有return时,会先进入finally中。如果finally中有return的话,那么会直接return出去,就不会回到try和catch中的return了。
34 0
|
11月前
|
Java 编译器 程序员
try with resources简洁的异常捕获机制
try with resources简洁的异常捕获机制
71 0
如何用c++实现异常处理
如何用c++实现异常处理
如何用c++实现异常处理
|
Dart JavaScript
[Flutter]足够入门的Dart语言系列之流程控制语句:中断和异常(continue/break、try...catch)
循环的执行是通过循环条件来控制的,但是,有时我们想要通过额外的条件判断,来决定是否中断执行,或者中断本次循环而继续执行下次及之后的循环;此外,我们需要对于异常情况的处理...
334 0
[Flutter]足够入门的Dart语言系列之流程控制语句:中断和异常(continue/break、try...catch)
|
Go
工作用Go: 异步任务怎么写5 | 异步任务: 能否更优雅点
工作用Go: 异步任务怎么写5 | 异步任务: 能否更优雅点
217 0
工作用Go: 异步任务怎么写5 | 异步任务: 能否更优雅点
|
Java 程序员 Go
Go+ 高级for循环、异常处理
channel < -是Go+里面的一个类型,叫channel,中文名叫管道,是Go+之间的一种通信机制,我们可以使用channel发送或者去接受数据,有点类似于Java的流编程。箭头方向表示数据的传递方向。
192 0
|
程序员 C#
终于明白了 C# 中 Task.Yield 的用途
原文:终于明白了 C# 中 Task.Yield 的用途 最近在阅读 .NET Threadpool starvation, and how queuing makes it worse 这篇博文时发现文中代码中的一种 Task 用法之前从未见过,在网上看了一些资料后也是云里雾里不知其解,很是困扰。
1168 0