本文由 CodeMotion原创,转载请声明。
一.前言
上一篇,我们观察了try catch finally 面向CLR真实的结构,知道了双层过滤的机制,在异步编程模型中要注意下面这些情况。
二.注意多线程AsyncTask
public static void TaskCatch()
{
try
{
var task = new Task(()=>throw new Exception());
task.Start();
}
catch (Exception e)
{
//此时不能捕捉异常
}
}
上面的这段代码无法捕捉在task中产生的异常,因为线程栈或者说是上下文无法衔接了。
task 中的异常无法传递给调用他的上一层try过滤。
解决方法很简单,在上一层try中同步下线程栈,可以使用task.wait()或者await task
关于同步 (异步Task) 其实也有很多的注意事项,尤其是在UI线程中使用要特别小心,可以参考这篇文章
C# 异步async 与 UI线程互锁问题分析处理
三.注意AsyncVoid(慎用)
static async void ThrowExceptionAsync()
{
throw new Exception();
}
public static void TaskCatch()
{
try
{
ThrowExceptionAsync();
}
catch (Exception)
{
throw;//此时不能捕捉异常
}
}
这种情况,异常无法传递给调用他的上一层try过滤。为什么呢?因为此时堆栈帧已经发生了变化
这一点可以借助VS看到。
解决方法:
1.将可能发生异常的异步方法改成同步方法,或使用async task;
2.将try catch 放在异步方法中,并在此处理掉异常。
四.总结
多线程异步同步是个很大的话题,针对AsyncViod,在面向CLR端的IL代码也做了自动调整。
在异步方法或多线程异步时,我们需要小心使用try catch 的“冒泡“机制。尽量使用AsyncTask代替AsyncViod。且AsyncViod搭配await想实现同步功能时,并不算真正的同步,对于AsyncViod一定要慎用。