task好像沒有在線程外取消任務的操作,沒有類似於Thread.Abort();這樣停止線程的操作,當然,也可以在task生成時,把task所屬的線程記錄下來,然后用Thread.Abort()停止,因為task本身也是附屬與這個線程的,線程停了,task肯定也停了,不過這樣那還不如直接用Thread做多線程異步處理了,何必廢二遍事。
在task內部有兩種方式關閉線程,一種是引發異常,一種是用用Token.IsCancellationRequested自己判斷狀態關閉。
在task外部CancellationTokenSource.Cancel()。//通知關閉Task
Label Label1 = sp.FindName("Label1") as Label; CancellationTokenSource CTS = new CancellationTokenSource(); CancellationToken Token = CTS.Token; //1.new方式實例化一個Task,需要通過Start方法啟動 Task task = new Task(() => { //置為后台線程(Task默認就是為后台線程) //Thread.CurrentThread.IsBackground = true;//后台線程在應用程序退出時都會自動結束(主窗體關閉后台線程自動結束) WorkTask(Label1, Token); }, Token); task.Start();
//關閉線程 CancellationTokenSource CTS = CT.CTS; CTS.Cancel();//通知關閉Task
void WorkTask(Label ThisLabel, CancellationToken Token) { try { #region 更新下載進度 while (true) { #region //關閉線程 Token.ThrowIfCancellationRequested();//引發異常關閉線程(二選一) //if (Token.IsCancellationRequested) //{ // //或者判斷狀態關閉線程(二選一) // return; //} //if (Token.IsCancellationRequested) //{ // System.Threading.Thread.CurrentThread.Abort();//或者使用當前線程Abort()也可以 //} #endregion // 更新下載進度 this.Dispatcher.BeginInvoke(new Action(() => { ThisLabel.Content = "下載中...." + DateTime.Now.ToString("HH:mm:ss") + "/" + DateTime.Now.ToString("HH:mm:ss"); })); // 后台線程停頓1秒 Thread.Sleep(1000); } #endregion } catch (Exception ex) { LogHelper.AddLog(AbnormalType.info, "YiBuTest2,Thread1異常:-->" + ex.Message); } }
取消任務
我們知道task是並行計算的,比如說主線程在某個時刻由於某種原因要取消某個task的執行,我們能做到嗎? 當然我們可以做到。
在4.0中給我們提供一個“取消標記”叫做CancellationTokenSource.Token,在創建task的時候傳入此參數,就可以將主線程和任務相
關聯,然后在任務中設置“取消信號“叫做ThrowIfCancellationRequested來等待主線程使用Cancel來通知,一旦cancel被調用。task將會
拋出OperationCanceledException來中斷此任務的執行,最后將當前task的Status的IsCanceled屬性設為true。看起來是不是很抽象,
沒關系,上代碼說話。
1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 var cts = new CancellationTokenSource();
10 var ct = cts.Token;
11
12 Task task1 = new Task(() => { Run1(ct); }, ct);
13
14 Task task2 = new Task(Run2);
15
16 try
17 {
18 task1.Start();
19 task2.Start();
20
21 Thread.Sleep(1000);
22
23 cts.Cancel();
24
25 Task.WaitAll(task1, task2);
26 }
27 catch (AggregateException ex)
28 {
29 foreach (var e in ex.InnerExceptions)
30 {
31 Console.WriteLine("\nhi,我是OperationCanceledException:{0}\n", e.Message);
32 }
33
34 //task1是否取消
35 Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled);
36 Console.WriteLine("task2是不是被取消了? {0}", task2.IsCanceled);
37 }
38
39 Console.Read();
40 }
41
42 static void Run1(CancellationToken ct)
43 {
44 ct.ThrowIfCancellationRequested();
45
46 Console.WriteLine("我是任務1");
47
48 Thread.Sleep(2000);
49
50 ct.ThrowIfCancellationRequested();
51
52 Console.WriteLine("我是任務1的第二部分信息");
53 }
54
55 static void Run2()
56 {
57 Console.WriteLine("我是任務2");
58 }
59 }
從圖中可以看出
①:Run1中的Console.WriteLine("我是任務1的第二部分信息"); 沒有被執行。
②:Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled); 狀態為True。
也就告訴我們Run1中途被主線程中斷執行,我們coding的代碼起到效果了。