标签:
从《.Net 异步随手记(二)》来看,总感觉还差点儿什么,就是对不同情况的处理。比如当一个 Task 完成了后,我想让它继续执行 T1,如果被取消了就去执行 T2,如果...就去执行 T3,那怎么写呢?
过程是痛苦的,我笨了两天,终于搞通了。之前一直疑惑,为什么引发了 CancellationTokenSource 的 Cancel 方法,捕捉到的 Task 的 IsCanceled 属性依然是 False,今天晚上终于捕捉到了,看来还是自己写的有问题,不废话了,把代码记录一下:
1 namespace TaskConsole 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 while (true) 8 { 9 var enter = Console.ReadLine(); 10 11 if (enter.ToLower() == "continue") 12 { 13 cancelSource = new CancellationTokenSource(); 14 token = cancelSource.Token; 15 var task = Entry(); 16 Console.WriteLine(task.Status); 17 } 18 else if(enter.ToLower() == "cel") { 19 cancelSource.Cancel(); 20 } 21 else { break; } 22 } 23 } 24 25 26 async static Task DoWork(string workerName) 27 { 28 int count = 0; 29 30 while (count<10) 31 { 32 if (token.IsCancellationRequested) 33 { 34 Console.WriteLine("用户主动取消了任务"); 35 token.ThrowIfCancellationRequested(); 36 } 37 38 count++; 39 Console.WriteLine("{0} count {1} @ Thread Id {2}", workerName, count, System.Threading.Thread.CurrentThread.ManagedThreadId); 40 await Task.Delay(2000); 41 } 42 } 43 44 async static Task DoCancel(Task callbacker) 45 { 46 //await Task.Delay(2000); 47 Console.WriteLine("Do Cancel 任务运行了"); 48 } 49 50 async static Task DoContinue(Task callbacker) 51 { 52 //await Task.Delay(1000); 53 //Console.WriteLine("Continue 任务运行了 @ Task is {1}", callbacker.Status); 54 Console.WriteLine("Do Continue 运行了"); 55 } 56 57 async static Task Entry() 58 { 59 { 60 var taskWorker = Task.Factory.StartNew(() => DoWork("工作者1")); 61 try 62 { 63 await taskWorker.Result; 64 Console.WriteLine("taskworker 已经完成,是被取消的? {0}", taskWorker.Result.IsCanceled); 65 } 66 catch (OperationCanceledException) 67 { 68 Console.WriteLine("OperationCanceledException 异常,任务是被取消的? {0}", taskWorker.Result.IsCanceled); 69 } 70 71 var c1 = taskWorker.Result.ContinueWith(backer => DoCancel(backer), TaskContinuationOptions.OnlyOnCanceled); 72 var c2 = taskWorker.Result.ContinueWith(backer => DoContinue(backer), TaskContinuationOptions.OnlyOnRanToCompletion); 73 } 74 } 75 76 static CancellationTokenSource cancelSource; 77 static CancellationToken token; 78 } 79 }
从代码可以看出,C1 = 的是 taskWorker 的 Result 的 ContinueWith,也就是说,Token 真正引发的取消操作是作用于 DoWork 方法内的,而 taskWorker 并不是 DoWork 这个异步方法的引用,而是被 Factory“创建出来的某个运行 DoWork 的 Task”。因此,想要 C1、C2起作用,必须侦测的是 DoWork 方法到底是完成了还是被取消了,而 DoWork 方法是 taskWorker 的 Result,因此代码写成这样,运行结果就正确了。
输入 continue 启动程序,如果正常执行结束,将会是这样
中途输入 cel 来手动取消,将会是这样
感谢自己这脑袋终于想明白了,总结,如果写的是
1 var c1 = taskWorker.ContinueWith(backer => DoCancel(backer), TaskContinuationOptions.OnlyOnCanceled); 2 var c2 = taskWorkert.ContinueWith(backer => DoContinue(backer), TaskContinuationOptions.OnlyOnRanToCompletion);
那 C1 就永远不会有机会运行了,因为无论 DoWork 是正常结束还是被取消了,被工厂创建出来的那个 Task (也就是 taskWorker 所指向的对象)在 DoWork 返回之后都是 RanToCompletion。
标签:
原文地址:http://www.cnblogs.com/cinlap/p/5763287.html