常规Thread中处理异常

使用Thread创建的子线程,需要在委托中捕捉,无法在上下文线程中捕捉

static void Main(string[] args)
{
ThreadStart threadStart = DoWork;
Thread thread = new Thread(threadStart);
thread.Start();
thread.Join();
}
static void DoWork()
{
try
{
throw new Exception("子线程出现异常了");
}
catch (Exception ex)
{
Trace.Assert(false, "Catch In Delegate");
}
}

Task中处理异常

1.仍然可以在委托中捕获异常

2.可以捕获Task.Wait() 或者 Task.Result 的 AggregateException 异常

try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine($"Error: {ex.GetType().Name}");
foreach (Exception item in ex.InnerExceptions)
{
Console.WriteLine($"{item.GetType().Name}, {item.Message}");
}
}

AggregateException 是并行任务中捕获的一组异常

通过延续任务捕获前驱任务中的异常

static void Main(string[] args)
{
Task task = Task.Run(() => throw new Exception("前驱任务异常了"));
Task faultedTask = task.ContinueWith(antecedentTask =>
{
antecedentTask.Exception.Handle(eachE =>
{
Console.WriteLine($"Error: {eachE.Message}");
return true;
});
},TaskContinuationOptions.OnlyOnFaulted);
faultedTask.Wait();
}

前驱任务:使用Run书写的第一个任务就是前驱任务

延续任务:在一个任务后使用ContinueWith添加的任务就是延续任务,延续一般是一个全新的工作线程

TaskContinuationOptions:指定延续任务时的可配置项,默认情况下前驱任务完成后,立即执行延续任务,OnlyOnFaulted表示只有前驱任务失败(出异常的时候)才会执行这一个延续任务

Task.Exception也是一个AggregateException 异常

注意:

1.当指定的TaskContinuationOptions与前驱任务运行结果不一致时,强制调用延续任务Wait()会引发TaskCanceledException异常

static void Main(string[] args)
{
Task task = new Task(() =>
{
Console.WriteLine("前驱动任务执行中...");
});
Task faultedTask = task.ContinueWith(antecedentTask =>
{
Console.WriteLine("延续动任务执行中...");
}, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
try
{
faultedTask.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine($"Error: {ex.GetType().Name}");
foreach (Exception item in ex.InnerExceptions)
{
Console.WriteLine($"{item.GetType().Name}, {item.Message}");
}
}
Console.WriteLine($"前驱任务状态{task.Status}");
Console.WriteLine($"延续任务状态{faultedTask.Status}");
}

Ctrl+F5 输出

补充:

假如在前驱任务中出现了异常,如OnlyOnFaulted所愿,会执行faultedTask任务,并且在faultedTask.Wait()中不会捕捉到前驱任务的异常,具体看下面一点

2.延续任务虽然在异步任务中提供了类似if else 的ContinueWith但是在异常处理上还是有点局限,看一个例子

static void Main(string[] args)
{
Task task = Task.Run(()
=>
throw new Exception("前驱任务异常了"));
Task task1 = task.ContinueWith(antecedentTask =>
{
throw new Exception("延续任务1异常了");
});
Task task2 = task1.ContinueWith(antecedentTask =>
{
throw new Exception("延续任务2异常了");
});
Task task3 = task2.ContinueWith(antecedentTask =>
{
throw new Exception("延续任务3异常了");
});
try
{
task3.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine($"Error: {ex.GetType().Name}");
foreach (Exception item in ex.InnerExceptions)
{
Console.WriteLine($"{item.GetType().Name}, {item.Message}");
}
}
}

Ctrl+F5 输出

其实这样也可以理解,task3.Wait()只会收集task3所在工作线程上的异常,遗憾的是Task.Exception.InnerExceptions是一个只读集合,这样一来,每个任务的异常只能在各自委托中处理了,事实上也应该如此,可以使用TaskContinuationOptions进行灵活控制

使用CancellationTokenSource取消任务

static void Main(string[] args)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.Token.Register(() =>
{
Console.WriteLine("任务取消了");
});
cancellationTokenSource.CancelAfter();
Task task = Task.Run(() =>
{
while (true && !cancellationTokenSource.IsCancellationRequested)
{
Console.WriteLine("任务执行中...");
Thread.Sleep();
}
},
cancellationTokenSource.Token);
task.Wait();
Console.WriteLine($"任务的最终状态是:{task.Status}");
}

Ctrl+F5 输出

正常取消的任务最终状态是 RanToCompletion ,这里要注意的是,CancelAfter()是在这个方法调用的那一刻开始计时的(并非以Run开始计时,好吧,很好理解,我却疑惑了半天)

小结:

结合 TaskContinuationOptions 和 CancellationTokenSource 可以很好处理多任务中异常,但是编写在异步程序还是很繁琐的,具体的在下一个笔记中会结合C#5.0做一个比较

C#多线程中的异常处理的更多相关文章

  1. C#多线程中的异常处理(转载)

    常规Thread中处理异常 使用Thread创建的子线程,需要在委托中捕捉,无法在上下文线程中捕捉 static void Main(string[] args) { ThreadStart thre ...

  2. Java多线程中的异常处理

    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉.这一点是通过java.lang.Run ...

  3. C++ std::thread 多线程中的异常处理

    环境: VS2019 包含头文件: #include <iostream>#include<thread>#include<exception> 线程函数采用try ...

  4. web应用中的异常处理

    楼主前几天写了一篇“Java子线程中的异常处理(通用)”文章,介绍了在多线程环境下3种通用的异常处理方法. 但是平时大家的工作一般是基于开发框架进行的(比如Spring MVC,或Spring Boo ...

  5. 编写高质量代码改善C#程序的157个建议——建议85:Task中的异常处理

    建议85:Task中的异常处理 在任何时候,异常处理都是非常重要的一个环节.多线程与并行编程中尤其是这样.如果不处理这些后台任务中的异常,应用程序将会莫名其妙的退出.处理那些不是主线程(如果是窗体程序 ...

  6. 编写高质量代码改善C#程序的157个建议——建议66:正确捕获多线程中的异常

    建议66:正确捕获多线程中的异常 多线程的异常处理需要采用特殊的方式.一下这种方式会存在问题: try { Thread t = new Thread((ThreadStart)delegate { ...

  7. 转:Spring Boot应用中的异常处理

    引自:https://www.cnblogs.com/yangfanexp/p/7616570.html 楼主前几天写了一篇“Java子线程中的异常处理(通用)”文章,介绍了在多线程环境下3种通用的异 ...

  8. 【repost】JS中的异常处理方法分享

    我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...

  9. c#初学-多线程中lock用法的经典实例

    本文转载自:http://www.cnblogs.com/promise-7/articles/2354077.html 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被 ...

随机推荐

  1. 转载 jQueryEasyUI Messager基本使用

    http://www.cnblogs.com/libingql/archive/2011/07/17/2109020.html 一.jQueryEasyUI下载地址 http://www.jeasyu ...

  2. linux上安装redis的踩坑过程

    redis用处很广泛,我不再啰嗦了,我按照网上教程想在linux上安装下,开始了踩坑过程,网上买了一个linux centos7.3,滴滴云的,巨坑无比啊,不建议大家用这家的! redis 为4.0, ...

  3. Scala编程入门---数组操作之Array.ArrayBuffer以及遍历数组

    在Scala中,Array代表的含义与Java类似,也是长度不可改变的数组.此外,由于Scala与java都是运行在JVM中,双方可以互相调用,因此Scala数组底层实际上是java数组.列如字符串数 ...

  4. 佛祖镇楼,BUG避易

    def FZZL(): print(" _ooOoo_ ") print(" o8888888o ") print(" 88 . 88 ") ...

  5. CSS学习笔记二:css 画立体图形

    继上一次学了如何去运用css画平面图形,这一次学如何去画正方体,从2D向着3D学习,虽然有点满,但总是一个过程,一点一点积累,然后记录起来. Transfrom3D 在这一次中运用到了一下几种属性: ...

  6. Python《学习手册:第二章-习题》

    什么是Python解释器? Python解释器是运行Python程序的程序. 什么是源代码? 源代码是为程序所写的语句:它包括文本文件(通常以.py为文件名结尾)的文件. 什么是字节码? 字节码是Py ...

  7. Eclipse开发前,常用设置

    设置工作空间的项目编码, 防止出现乱码    Window - Preferences - General - Workspace    将"Text file encoding" ...

  8. Unity3D学习(八):《Unity Shader入门精要》——透明效果

    前言 在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道. Unity中通常使用两种方法来实现透明 :(1)透明度测试(AlphaTest)(2)透明度混合(AlphaBlend).前者往 ...

  9. Linux用户登录日志查询

    # 1 utmp.wtmp.btmp文件 Linux用户登录信息放在三个文件中: 1 /var/run/utmp:记录当前正在登录系统的用户信息,默认由who和w记录当前登录用户的信息,uptime记 ...

  10. Jmeter4.0分布式测试时启动Jmeter.server时报错

       最近又开始研究Jmeter,将新版本4.0下载下来体验,准备远程分布式测试,又出现一些问题,废话不多说,直入主题把! Windows 系统启动Jmeter 4.0的JmeterServer.ba ...