C#多線程中的異常處理操作示例
本文實(shí)例講述了C#多線程中的異常處理操作。分享給大家供大家參考,具體如下:
常規(guī)Thread中處理異常
使用Thread創(chuàng)建的子線程,需要在委托中捕捉,無(wú)法在上下文線程中捕捉
static void Main(string[] args) { ThreadStart threadStart = DoWork; Thread thread = new Thread(threadStart); thread.Start(); thread.Join(); } static void DoWork() { try { throw new Exception("子線程出現(xiàn)異常了"); } 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 是并行任務(wù)中捕獲的一組異常
通過(guò)延續(xù)任務(wù)捕獲前驅(qū)任務(wù)中的異常
static void Main(string[] args) { Task task = Task.Run(() => throw new Exception("前驅(qū)任務(wù)異常了")); Task faultedTask = task.ContinueWith(antecedentTask => { antecedentTask.Exception.Handle(eachE => { Console.WriteLine($"Error: {eachE.Message}"); return true; }); },TaskContinuationOptions.OnlyOnFaulted); faultedTask.Wait(); }
前驅(qū)任務(wù):使用Run書寫的第一個(gè)任務(wù)就是前驅(qū)任務(wù)
延續(xù)任務(wù):在一個(gè)任務(wù)后使用ContinueWith添加的任務(wù)就是延續(xù)任務(wù),延續(xù)一般是一個(gè)全新的工作線程
TaskContinuationOptions:指定延續(xù)任務(wù)時(shí)的可配置項(xiàng),默認(rèn)情況下前驅(qū)任務(wù)完成后,立即執(zhí)行延續(xù)任務(wù),OnlyOnFaulted表示只有前驅(qū)任務(wù)失敗(出異常的時(shí)候)才會(huì)執(zhí)行這一個(gè)延續(xù)任務(wù)
Task.Exception也是一個(gè)AggregateException 異常
注意:
1.當(dāng)指定的TaskContinuationOptions與前驅(qū)任務(wù)運(yùn)行結(jié)果不一致時(shí),強(qiáng)制調(diào)用延續(xù)任務(wù)Wait()會(huì)引發(fā)TaskCanceledException異常
static void Main(string[] args) { Task task = new Task(() => { Console.WriteLine("前驅(qū)動(dòng)任務(wù)執(zhí)行中..."); }); Task faultedTask = task.ContinueWith(antecedentTask => { Console.WriteLine("延續(xù)動(dòng)任務(wù)執(zhí)行中..."); }, 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($"前驅(qū)任務(wù)狀態(tài){task.Status}"); Console.WriteLine($"延續(xù)任務(wù)狀態(tài){faultedTask.Status}"); }
Ctrl+F5 輸出
補(bǔ)充:
假如在前驅(qū)任務(wù)中出現(xiàn)了異常,如OnlyOnFaulted所愿,會(huì)執(zhí)行faultedTask任務(wù),并且在faultedTask.Wait()中不會(huì)捕捉到前驅(qū)任務(wù)的異常,具體看下面一點(diǎn)
2.延續(xù)任務(wù)雖然在異步任務(wù)中提供了類似if else 的ContinueWith但是在異常處理上還是有點(diǎn)局限,看一個(gè)例子
static void Main(string[] args) { Task task = Task.Run(() => throw new Exception("前驅(qū)任務(wù)異常了")); Task task1 = task.ContinueWith(antecedentTask => { throw new Exception("延續(xù)任務(wù)1異常了"); }); Task task2 = task1.ContinueWith(antecedentTask => { throw new Exception("延續(xù)任務(wù)2異常了"); }); Task task3 = task2.ContinueWith(antecedentTask => { throw new Exception("延續(xù)任務(wù)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 輸出
其實(shí)這樣也可以理解,task3.Wait()只會(huì)收集task3所在工作線程上的異常,遺憾的是Task.Exception.InnerExceptions是一個(gè)只讀集合,這樣一來(lái),每個(gè)任務(wù)的異常只能在各自委托中處理了,事實(shí)上也應(yīng)該如此,可以使用TaskContinuationOptions進(jìn)行靈活控制
使用CancellationTokenSource取消任務(wù)
static void Main(string[] args) { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.Token.Register(() => { Console.WriteLine("任務(wù)取消了"); }); cancellationTokenSource.CancelAfter(2000); Task task = Task.Run(() => { while (true && !cancellationTokenSource.IsCancellationRequested) { Console.WriteLine("任務(wù)執(zhí)行中..."); Thread.Sleep(300); } }, cancellationTokenSource.Token); task.Wait(); Console.WriteLine($"任務(wù)的最終狀態(tài)是:{task.Status}"); }
Ctrl+F5 輸出
正常取消的任務(wù)最終狀態(tài)是 RanToCompletion ,這里要注意的是,CancelAfter()是在這個(gè)方法調(diào)用的那一刻開(kāi)始計(jì)時(shí)的(并非以Run開(kāi)始計(jì)時(shí),好吧,很好理解,我卻疑惑了半天)
小結(jié):
結(jié)合 TaskContinuationOptions 和 CancellationTokenSource 可以很好處理多任務(wù)中異常,但是編寫在異步程序還是很繁瑣的,具體的在下一個(gè)筆記中會(huì)結(jié)合C#5.0做一個(gè)比較
更多關(guān)于C#相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《C#常見(jiàn)控件用法教程》、《WinForm控件用法總結(jié)》、《C#數(shù)據(jù)結(jié)構(gòu)與算法教程》、《C#面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》及《C#程序設(shè)計(jì)之線程使用技巧總結(jié)》
希望本文所述對(duì)大家C#程序設(shè)計(jì)有所幫助。
上一篇:C#中的多線程小試牛刀
欄 目:C#教程
下一篇:C#如何使用Bogus創(chuàng)建模擬數(shù)據(jù)示例代碼
本文標(biāo)題:C#多線程中的異常處理操作示例
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/4764.html
您可能感興趣的文章
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)多線程下載文件的方法
- 01-10C#實(shí)現(xiàn)多線程寫入同一個(gè)文件的方法
- 01-10C#獲取進(jìn)程或線程相關(guān)信息的方法
- 01-10C#通過(guò)Semaphore類控制線程隊(duì)列的方法
- 01-10C#線程隊(duì)列用法實(shí)例分析
- 01-10C#中查找Dictionary中的重復(fù)值的方法
- 01-10C#實(shí)現(xiàn)ComboBox控件顯示出多個(gè)數(shù)據(jù)源屬性的方法
- 01-10C#將圖片存放到SQL SERVER數(shù)據(jù)庫(kù)中的方法
- 01-10關(guān)于nancy中的身份驗(yàn)證


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過(guò)重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開(kāi)原生自帶讀寫NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 04-02jquery與jsp,用jquery