使用线程池(4)

实现一个取消选项

简介

当需要中断线程池上的异步操作时,有三种方法实现异步操作的取消:
1. 轮询来检查CancellationToken.IsCancellationRequested属性;
2. 抛出一个OperationCancelledException异;
3. 注册一个回调函数。

以下是代码实践:

using System;
using System.Threading;

namespace 实现一个取消选项
{
    internal class Program
    {
        private static void Main()
        {
            using (var cts=new CancellationTokenSource())
            {
                var token = cts.Token;
                ThreadPool.QueueUserWorkItem(_ => AsyncOperation1(token));
                Thread.Sleep(TimeSpan.FromSeconds(2));
                cts.Cancel();
            }

            using (var cts = new CancellationTokenSource())
            {
                var token = cts.Token;
                ThreadPool.QueueUserWorkItem(_ => AsyncOperation2(token));
                Thread.Sleep(TimeSpan.FromSeconds(2));
                cts.Cancel();
            }

            using (var cts = new CancellationTokenSource())
            {
                var token = cts.Token;
                ThreadPool.QueueUserWorkItem(_ => AsyncOperation3(token));
                Thread.Sleep(TimeSpan.FromSeconds(2));
                cts.Cancel();
            }

            Console.ReadKey();
        }

        /*轮询来检查CancellationToken.IsCancellationRequested属性。如果该属性为true,
         * 则说明操作需要被取消,我们必须放弃该操作。
         */
        private static void AsyncOperation1(CancellationToken token)
        {
            Console.WriteLine("Starting the first task");
            for (var i = 0; i < 5; i++)
            {
                if (token.IsCancellationRequested)
                {//取消操作的过程放在这里
                    Console.WriteLine("The first task has been canceled.");
                    return;
                }
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
            Console.WriteLine("The first task has completed succesfully");
        }

        /*抛出一个OperationCancelledException异常。这允许在操作之外
         *控制取消过程,即需要取消操作时,通过操作之外的代码来处理。
         */
        private static void AsyncOperation2(CancellationToken token)
        {
            try
            {
                Console.WriteLine("Starting the second task");

                for (var i = 0; i < 5; i++)
                {
                    token.ThrowIfCancellationRequested();
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }
                Console.WriteLine("The second task has completed successfully");
            }
            catch (OperationCanceledException)
            {//取消操作的过程放在这里
                Console.WriteLine("The second task has been canceled.");
            }
        }

        /*注册一个回调函数。当操作被取消时,在线程池将调用改回调函数。
         *这允许链式传递一个取消逻辑到另一个异步操作中。
         */
        private static void AsyncOperation3(CancellationToken token)
        {
            var cancellationFlag = false;
            token.Register(()=>cancellationFlag=true);//回调函数可以放取消后的操作
            Console.WriteLine("Starting the third task");
            for (var i = 0; i < 5; i++)
            {
                if (cancellationFlag)
                {//取消操作的过程放在这里
                    Console.WriteLine("The third task has been canceled.");
                    return;
                }
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
            Console.WriteLine("The third task has completed successfully");
        }
    }
}

总结

  1. ancellationTokenSource和CancellationToken两个新类是在.NET4.0被引入,目前是实现异步操作的取消操作的事实标准;
  2. 种取消过程根据实际要选取。

备注:学习《Multithreading in C# 5.0 Cookbook》Eugene Agafonov著的总结,以备日后查询。

posted on 2017-09-23 09:55  五月槐花  阅读(85)  评论(0编辑  收藏  举报

导航