一、Task和多線程以及異常的捕獲示例代碼:
static void Main(string[] args) { // 產(chǎn)生CancellationToken的類,該類允許使用Cancel方法終止線程 // 也可以使用CancellationTokenSource.CreateLinkedTokenSource創(chuàng)建 // 一組相關(guān)的Token,任意一個取消都取消 CancellationTokenSource ts = new CancellationTokenSource(); CancellationToken ct = ts.Token; Task t = null; t = new Task(() => { for (int i = 1; i < 11; i++) { // 調(diào)用Cancel方法,狀態(tài)為true(表示已經(jīng)取消了) if (!ts.IsCancellationRequested) { if (i == 5) { // 該異常不會直接被主線程捕獲 throw new Exception("數(shù)字是5,非法!"); } } else { Console.WriteLine("用戶取消"); // 拋出異常,強制取消子線程 ct.ThrowIfCancellationRequested(); } Console.WriteLine(i); Thread.Sleep(500); } }, ct); t.Start(); // 注冊Cancel之后的引發(fā)的事件,注意Exception也可以在這里捕獲 t.ContinueWith((task) => { // 只有調(diào)用Cancel方法才會被設(shè)置為True Console.WriteLine(t.IsCanceled); // 無論何種情況,只要完成了就是True Console.WriteLine(t.IsCompleted); // 只要有異常,為True(哪怕是ThrowIfCancellationRequested異常) Console.WriteLine(t.IsFaulted); // 捕獲各種各樣的異常 foreach (var item in task.Exception.InnerExceptions) { Console.WriteLine(item.Message); } }); Console.ReadLine(); // 取消任務(wù) ts.Cancel(); Thread.Sleep(Timeout.Infinite); }
結(jié)論:
1、無論任何異常都會終止子線程。
2、異常發(fā)生之后,只有在Task的Wait/WaitAll/WaitAny/Result或者Continue方法才可以捕獲異常,主線程不可能,因為是子線程中的異常。
二、Task的任務(wù)先后順序(允許嵌套任務(wù)),同時允許把線程掛接到主線程上執(zhí)行返回結(jié)果(避免以前Thread和WinForm控件交互時候發(fā)生的“不是由本線程創(chuàng)建的控件異常……”問題):
static void Main(string[] args) { CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; Task t = new Task(() => { Console.WriteLine("主任務(wù)開始……,包含3個子任務(wù):"); Task.Factory.StartNew(() => { Thread.Sleep(2000); Console.WriteLine("任務(wù)一"); }, // 掛接到主線程,這樣主線程會自動等待子線程完成后完成 TaskCreationOptions.AttachedToParent ); Task.Factory.StartNew(() => { Thread.Sleep(500); Console.WriteLine("任務(wù)二"); }, TaskCreationOptions.AttachedToParent); Task.Factory.StartNew(() => { Thread.Sleep(1000); Console.WriteLine("任務(wù)三"); }, TaskCreationOptions.AttachedToParent); }, ct); t.ContinueWith((Task) => { Console.WriteLine("子任務(wù)都完成,主任務(wù)結(jié)束。"); // 指定上下文的同步塊,防止跨線程訪問控件的問題(控制臺程序不能使用,WinForm啥可以) },TaskScheduler.FromCurrentSynchronizationContext()); t.Start(); Thread.Sleep(Timeout.Infinite); }
相比較原來的Wait而言,不會卡死子線程,而且又可以多任務(wù)運行。
欲想知道更多關(guān)于線程操作的東西,可以參考:
MSDN,并行處理系列篇:http://msdn.microsoft.com/zh-cn/library/vstudio/3e8s7xdd(v=vs.110).aspx
新聞熱點
疑難解答