返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C# CancellationToken和CancellationTokenSource的用法详解
  • 729
分享到

C# CancellationToken和CancellationTokenSource的用法详解

2024-04-02 19:04:59 729人浏览 薄情痞子
摘要

目录CancellationToken通过ReGISter方法注册的服务只会执行一次!CancellationTokenSource使用场景一使用场景二使用场景三Cancellati

CancellationToken

  CancellationToken有一个构造函数,可以传入一个bool类型表示当前的CancellationToken是否是取消状态。另外,因为CancellationToken是一个结构体,所以它还有一个空参数的构造函数。 


    public CancellationToken();//因为是结构体,才有空构造函数,不过没什么作用
    public CancellationToken(bool canceled);

   属性如下:  


    //静态属性,获取一个空的CancellationToken,这个CancellationToken注册的回调方法不会被触发,作用类似于使用空构造函数得到的CancellationToken
    public static CancellationToken None { get; }
    //表示当前CancellationToken是否可以被取消
    public bool CanBeCanceled { get; }
    //表示当前CancellationToken是否已经是取消状态
    public bool IsCancellationRequested { get; }
    //和CancellationToken关联的WaitHandle对象,CancellationToken注册的回调方法执行时通过这个WaitHandle实现的
    public WaitHandle WaitHandle { get; }

  常用方法:  


    //往CancellationToken中注册回调
    public CancellationTokenRegistration Register(Action callback);
    public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext);
    public CancellationTokenRegistration Register([NullableAttribute(new[] { 1, 2 })] Action<object?> callback, object? state);
    public CancellationTokenRegistration Register([NullableAttribute(new[] { 1, 2 })] Action<object?> callback, object? state, bool useSynchronizationContext);
    //当CancellationToken处于取消状态是,抛出System.OperationCanceledException异常
    public void ThrowIfCancellationRequested();

  常用的注册回调的方法是上面4个Register方法,其中callback是回调执行的委托,useSynchronizationContext表示是否使用同步上下文,state是往回调委托中传的参数值

  另外,Register方法会返回一个CancellationTokenRegistration结构体,当注册回调之后,可以调用CancellationTokenRegistration的Unregister方法来取消注册,这个Unregister方法会返回一个bool值,当成功取消时返回true,当取消失败(比如回调已执行)将返回false:  


    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    var cancellationTokenRegistration = cancellationTokenSource.Token.Register(() =>
    {
        Console.WriteLine("Canceled");//这里将不会执行输出
    });

    //cancellationTokenSource.Cancel();
    //var result = cancellationTokenRegistration.Unregister();//result = false

    var result = cancellationTokenRegistration.Unregister();//result = true
   cancellationTokenSource.Cancel();

   上面提到,CancellationToken可以使用构造函数直接构造,同时可以传入一个参数,表示当前的状态,需要注意的是,CancellationToken的状态最多可以改变一次,也就是从未取消变成已取消。

  如果构造时传入true,也就是说CancellationToken是已取消状态,这个时候注册的回调都会立即执行: 


    CancellationToken cancellationToken = new CancellationToken(true);
    cancellationToken.Register(() =>
    {
        Console.WriteLine("Canceled");//这里会立即执行输出Canceled
    });

  但如果构造时传入的是false,说明CancellationToken处于未取消状态,这时候注册的回到都会处于一个待触发状态:


    CancellationToken cancellationToken = new CancellationToken(false);
    cancellationToken.Register(() =>
    {
        Console.WriteLine("Canceled");//这里不会立即执行输出
    });

通过Register方法注册的服务只会执行一次!

  但一般的,如果传入false构造出来的CancellationToken,可以认为是不会触发的,因为它没有触发的方法!所以一般的,我们都不会直接使用构造函数创建CancellationToken,而是使用CancellationTokenSource对象来获取一个CancellationToken

CancellationTokenSource

  CancellationTokenSource可以理解为CancellationToken的控制器,控制它什么时候变成取消状态的一个对象,它有一个CancellationToken类型的属性Token,只要CancellationTokenSource创建,这个Token也会被创建,同时Token会和这个CancellationTokenSource绑定


    //表示Token是否已处于取消状态
    public bool IsCancellationRequested { get; }
    //CancellationToken 对象
    public CancellationToken Token { get; }

  可以直接创建一个CancellationTokenSource对象,同时指定一个时间段,当过了这段时间后,CancellationTokenSource就会自动取消了。

  CancellationTokenSource的取消有4个方法:  


    //立刻取消
    public void Cancel();
    //立刻取消
    public void Cancel(bool throwOnFirstException);
    //延迟指定时间后取消
    public void CancelAfter(int millisecondsDelay);
    //延迟指定时间后取消
    public void CancelAfter(TimeSpan delay);

  Cancel和两个CancelAfter方法没什么特别的,主要就是有一个延迟的效果,需要注意的是Cancel的两个重载之间的区别。

  首先,上面说道,CancellationToken状态只能改变一次(从未取消变成已取消),当CancellationToken时已取消状态时,每次往其中注册的回调都会立刻执行!当处于未取消状态时,注册进去的回调都会等待执行。

  需要注意的是,当在未取消状态下注册多个回调时,它们在执行时是一个类似栈的结构顺序,先注册后执行。

  而CancellationToken的Register可以注册多个回调,那他们可能都会抛出异常,throwOnFirstException参数表示在第一次报错时的处理行为.

  throwOnFirstException = true 表示立即抛出当前发生的异常,后续的回调将会取消执行  


    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    try
    {
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("1");
        });
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("2");//不会执行
        });

        cancellationTokenSource.Cancel(true);
    }
    catch (Exception ex)
    {
        //ex is System.Exception("1")
    }

   throwOnFirstException = false 表示跳过当前回调的异常,继续执行生效的回调,等所有的回调执行完成之后,再将所有的异常打包成一个System.AggregateException异常抛出来!


    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    try
    {
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("1");
        });
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("2");
        });

        cancellationTokenSource.Cancel(false);//相当于cancellationTokenSource.Cancel()
    }
    catch (Exception ex)
    {
        //ex is System.AggregateException:[Exception("2"),Exception("1")]
    }

   CancellationTokenSource还可以与其它CancellationToken关联起来,生成一个新的CancellationToken,当其他CancellationToken取消时,会自动触发当前的CancellationTokenSource执行取消动作!  

使用场景一

  当我们创建异步操作时,可以传入一个CancellationToken,当异步操作处于等待执行状态时,可以通过设置CancellationToken为取消状态将异步操作取消执行:  


    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    var task = new Task(() =>
    {
        Thread.Sleep(1500);//执行了2秒中代码
        Console.WriteLine("Execute Some Code");
    }, cancellationTokenSource.Token);

    task.Start();//启动,等待调度执行

    //发现不对,可以取消task执行
    cancellationTokenSource.Cancel();
    Thread.Sleep(1000);//等待1秒
    Console.WriteLine("Task状态:" + task.Status);//Canceled

   但是经常的,我们的取消动作可能不会那么及时,如果异步已经执行了,再执行取消时无效的,这是就需要我们自己在异步委托中检测了:  


    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    var task = new Task(() =>
    {
        Thread.Sleep(1500);//执行了2秒中代码
        cancellationTokenSource.Token.ThrowIfCancellationRequested();
        Console.WriteLine("Execute Some Code");
    }, cancellationTokenSource.Token);

    task.Start();//启动,等待调度执行

    Thread.Sleep(1000);////一段时间后发现不对,可以取消task执行
    cancellationTokenSource.Cancel();
    Thread.Sleep(1000);//等待1秒
    Console.WriteLine("Task状态:" + task.Status);//Canceled

使用场景二

   有时,我们希望在触发某个时间后,可以执行某些代码功能,但是在异步环境下,我们不能保证那些要执行的代码是否已准备好了,比如我们有一个Close方法,当调用Close后表示是关闭状态,如果我们相当程序处于关闭状态时执行一些通知,一般的,我们可能是想到采用事件模型,或者在Close方法传入事件委托,或者采用一些诸如模板设计这样的模型去实现: 


    class Demo
    {
        public void Close(Action callback)
        {
            //关闭
            Thread.Sleep(3000);

            callback?.Invoke();//执行通知
        }
    }

  或者  


    class Demo
    {
        public event Action Callback;

        public void Close()
        {
            //关闭
            Thread.Sleep(3000);

            Callback?.Invoke();//执行通知
        }
    }

  但是这就有问题了,如果是传入参数或者采用事件模型,因为前面说过了,如果在异步环境下,我们不能保证那些要执行的代码是否已准备好了,也许在执行Close方法时,程序还未注册回调。

  这个时候就可以使用CancellationToken来解决这个问题:  

  主需要往Token属性中注册回调而无需关注Close什么时候执行了

使用场景三

  有时候,我们写一个异步无限循环的方法去处理一些问题,而我们希望可以在方法外来停止它这个时候,我们就可以通过返回CancellationTokenSource来实现了:  


        public CancellationTokenSource Listen()
        {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

            //循环调度执行
            Task.Run(() =>
            {
                while (true)
                {
                    cancellationTokenSource.Token.ThrowIfCancellationRequested();

                    //循环执行一些操作
                    Thread.Sleep(1000);
                    Console.WriteLine("Run");
                }
            });

            return cancellationTokenSource;
        }

以上就是C# CancellationToken和CancellationTokenSource的用法详解的详细内容,更多关于C# CancellationToken和CancellationTokenSource的资料请关注编程网其它相关文章!

--结束END--

本文标题: C# CancellationToken和CancellationTokenSource的用法详解

本文链接: https://lsjlt.com/news/129028.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C# CancellationToken和CancellationTokenSource的用法详解
    目录CancellationToken通过Register方法注册的服务只会执行一次!CancellationTokenSource使用场景一使用场景二使用场景三Cancellati...
    99+
    2024-04-02
  • C#使用CancellationTokenSource取消Task的方法
    本篇的内容也很重要,因为涉及到了日常经常会碰到的取消任务操作。 从我个人了解到的情况,基本上大家都采用CancellationTokenSource方法来取消任务,因此这里就举几个简...
    99+
    2024-04-02
  • 运用示例简单讲解C#取消令牌CancellationTokenSource
    目录前言简单示例基础操作 定时取消关联取消 判断取消 源码探究构造入手 小插曲WaitHandle 注册操作 取消操作Cancel操作 CancelAfter操作 总结 前言 &nb...
    99+
    2024-04-02
  • 详解C++中string的用法和例子
    在C++中,string是一个表示字符串的标准库类。它提供了许多成员函数和操作符,用于在字符串中执行各种操作。以下是一些常见的str...
    99+
    2023-08-16
    C++
  • C/C++ extern和static的使用详解
    目录前言externstaticc++ static members in class总结前言 在讲到extern和static的时候先了解一下定义和声明的基本概念 定义(defin...
    99+
    2024-04-02
  • C语言中static和auto用法详解
    目录static的第一种用法:定义为静态变量static的第二种用法:有理说不清,直接代码见真知auto的用法:直接代码见真知总结static的第一种用法:定义为静态变量 何为静态变...
    99+
    2024-04-02
  • C++ std::function的用法详解
    类模版std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lamb...
    99+
    2024-04-02
  • C++中的memset用法详解
    memset简介 memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。 void *memset(void *s, int c, size_t n); s指向要...
    99+
    2023-02-04
    memset的用法 c++ memset用法
  • C# Invoke,begininvoke的用法详解
    在C#中,Invoke和BeginInvoke是用于在多线程编程中调用委托的方法。委托是一种可以存储对方法的引用的类型,可以用于异步...
    99+
    2023-08-08
    C#
  • c++中set的用法详解
    c++kquote>set 是一种存储不重复且有序元素的容器,元素的顺序由比较函数决定。创建 set 使用 set 语法,插入元素用 insert() 方法,查找元素用 find(...
    99+
    2024-05-01
    c++
  • C++ string.erase()用法详解
    标准库类型string表示可变长的字符序列。可以通过string类的erase()函数来对该字符序列进行删除操作。erase()函数共有3种格式,分别用来删除指定位置的字符、删除指定...
    99+
    2024-04-02
  • 【C++】:string用法详解
    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux的基础知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数据结构专栏:数据结构 个  人  主...
    99+
    2023-10-20
    c++ string
  • C#Newtonsoft.Json用法详解
    目录一、创建JSON对象二、创建JSON数组三、使用Linq to JSON查询四、将类对象序列化为Json五、将Json反序列化为类对象六、常用工具1.判断Json是否正确2.添加...
    99+
    2023-02-06
    C# Newtonsoft.Json
  • C和C++的区别详解
    目录通过程序来介绍1.iostream文件2.头文件名的区别C语言C++3.名称空间namespace封装性4.使用cout进行C++的输出指针和数组名的区别反汇编查看区别结论解引用...
    99+
    2024-04-02
  • c语言中static和extern的用法详细解析
    一,static和extern:大工程下我们会碰到很多源文档。文档a.c复制代码 代码如下:static int i; //只在a文档中用int j;  &nbs...
    99+
    2022-11-15
    c语言 extern static
  • C++ deque容器的用法详解
    deque(双端队列)是由一段一段的定量连续空间构成,可以向两端发展,因此不论在尾部或头部安插元素都十分迅速。 在中间部分安插元素则比较费时,因为必须移动其它元素。 deque容器的...
    99+
    2024-04-02
  • C++ pair的用法案例详解
    一、介绍 pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair。当然你也可以自定义一个结构体struct。不过大家都是为了方便,所以就直接用pair了。 pair...
    99+
    2024-04-02
  • C#中的数组用法详解
    目录一.简单数组(一维数组)1.数组的声明2.数组的初始化3.访问数组元素4.数组中使用引用类型二.多维数组三.锯齿数组四.Array类1.创建数组2.复制数组3.排序五.数组作为参...
    99+
    2024-04-02
  • C语言return的用法详解
    C语言return的用法有:1、对于返回值类型为void的函数,可以使用return语句来提前结束函数的执行;2、对于返回值类型不为void的函数,return语句的作用是将函数的执行结果返回给调用者;3、提前结束函数的执行,在函数内部,我...
    99+
    2023-10-22
    C语言 return
  • C++const的各种用法详解
    目录const的基本概念:一、const修饰基本数据类型 1.const修饰一般常量及数组  2.const修饰指针变量*及引用变量& ...
    99+
    2023-05-17
    C++ const用法介绍 C++ const用法 C++ const
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作