C#中可取消的Task

1、需求
我们知道task是并行计算的,比如说主线程在某个时刻由于某种原因要取消某个task的执行,我们能做到吗? 当然我们可以做到。
在4.0中给我们提供一个“取消标记”叫做CancellationTokenSource.Token,在创建task的时候传入此参数,就可以将主线程和任务相关联,然后在任务中设置“取消信号“叫做ThrowIfCancellationRequested来等待主线程使用Cancel来通知,一旦cancel被调用。task将会抛出OperationCanceledException来中断此任务的执行,最后将当前task的Status的IsCanceled属性设为true。
注意:一定要处理这个异常,可以通过调用Task.Result成员来获取这个异常。如果一直不查询Task的Exception属性。你的代码就永远注意不到这个异常的发生,如果不能捕捉到这个异常,垃圾回收时,抛出AggregateException,进程就会立即终止,这就是“牵一发动全身”,莫名其妙程序就自己关掉了,谁也不知道这是什么情况。所以,必须调用前面提到的某个成员,确保代码注意到异常,并从异常中恢复。因此可以将条用Task的某个成员来检查Task是否跑出了异常,通常调用Task的Result。下面看代码:

        static void Main(string[] args)
        {
            var cts = new CancellationTokenSource();
            var ct = cts.Token;

            Task task1 = new Task(() => { Run1(ct); }, ct);

            Task task2 = new Task(Run2);

            try
            {
                task1.Start();
                task2.Start();
//在这段时间内,ct.ThrowIfCancellationRequested();是不会被触发的
                Thread.Sleep(1000);
                cts.Cancel();
                //这时候会触发ct.ThrowIfCancellationRequested();

                Task.WaitAll(task1, task2);
            }
            catch (AggregateException ex)
            {
                foreach (var e in ex.InnerExceptions)
                {
                    Console.WriteLine("\nhi,我是OperationCanceledException:{0}\n", e.Message);
                }

                //task1是否取消
                //Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled);
                //Console.WriteLine("task2是不是被取消了? {0}", task2.IsCanceled);
            }
            Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled);
            Console.WriteLine("task2是不是被取消了? {0}", task2.IsCanceled);
            Console.Read();
        }

        static void Run1(CancellationToken ct)
        {
        //下面这句话是没有用的,因为这个时候没有收到Cancel的消息
            ct.ThrowIfCancellationRequested();

            Console.WriteLine("我是任务1");

            Thread.Sleep(2000);//是为了在Cancel的时候Run1没有执行完
//当上面等到1000ms多的时候实际上已经接收到Cancel的消息了,但是这个时候不会取消task的,只有调用下面这句话的时候才会取消task
            ct.ThrowIfCancellationRequested();

            Console.WriteLine("我是任务1的第二部分信息");
        }

        static void Run2()
        {
            Console.WriteLine("我是任务2");
        }

注意:
1、只有ct.ThrowIfCancellationRequested();才能真正的取消Task,此外,ct.ThrowIfCancellationRequested();的调用必须是接收到Cancel命令过来才会触发的。
2、个人认为:这样子的目的是为了接收到取消的时候,不会立马停止Task,而是只有在合适的时间停止。
2、Task的写法:

var cts = new CancellationTokenSource();
var ct = cts.Token;
Task task1 = new Task(() => { Run1(ct); }, ct);

你可能感兴趣的:(C#)