C#多线程中的异常处理操作示例
本文实例讲述了C#多线程中的异常处理操作。分享给大家供大家参考,具体如下:
常规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(2000); Task task = Task.Run(() => { while (true && !cancellationTokenSource.IsCancellationRequested) { Console.WriteLine("任务执行中..."); Thread.Sleep(300); } }, cancellationTokenSource.Token); task.Wait(); Console.WriteLine($"任务的最终状态是:{task.Status}"); }
Ctrl+F5 输出
正常取消的任务最终状态是 RanToCompletion ,这里要注意的是,CancelAfter()是在这个方法调用的那一刻开始计时的(并非以Run开始计时,好吧,很好理解,我却疑惑了半天)
小结:
结合 TaskContinuationOptions 和 CancellationTokenSource 可以很好处理多任务中异常,但是编写在异步程序还是很繁琐的,具体的在下一个笔记中会结合C#5.0做一个比较
更多关于C#相关内容感兴趣的读者可查看本站专题:《C#常见控件用法教程》、《WinForm控件用法总结》、《C#数据结构与算法教程》、《C#面向对象程序设计入门教程》及《C#程序设计之线程使用技巧总结》
希望本文所述对大家C#程序设计有所帮助。
上一篇:C#中的多线程小试牛刀
栏 目:C#教程
本文标题:C#多线程中的异常处理操作示例
本文地址:https://www.xiuzhanwang.com/a1/C_jiaocheng/4764.html
您可能感兴趣的文章
- 01-10C#停止线程的方法
- 01-10C#实现多线程下载文件的方法
- 01-10C#实现多线程写入同一个文件的方法
- 01-10C#获取进程或线程相关信息的方法
- 01-10C#通过Semaphore类控制线程队列的方法
- 01-10C#线程队列用法实例分析
- 01-10C#中查找Dictionary中的重复值的方法
- 01-10C#实现ComboBox控件显示出多个数据源属性的方法
- 01-10C#将图片存放到SQL SERVER数据库中的方法
- 01-10关于nancy中的身份验证
阅读排行
本栏相关
- 01-10C#通过反射获取当前工程中所有窗体并
- 01-10关于ASP网页无法打开的解决方案
- 01-10WinForm限制窗体不能移到屏幕外的方法
- 01-10WinForm绘制圆角的方法
- 01-10C#实现txt定位指定行完整实例
- 01-10WinForm实现仿视频播放器左下角滚动新
- 01-10C#停止线程的方法
- 01-10C#实现清空回收站的方法
- 01-10C#通过重写Panel改变边框颜色与宽度的
- 01-10C#实现读取注册表监控当前操作系统已
随机阅读
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法实例总结
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10SublimeText编译C开发环境设置
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-11ajax实现页面的局部加载
- 04-02jquery与jsp,用jquery