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