c# Task任务的取消方式

 更新时间:2024年12月31日 08:57:11   作者:皮皮君  
文章介绍了如何在C#中使用CancellationTokenSource和CancellationToken来取消任务,通过Task.Run方法和CancellationToken参数,可以控制任务的执行,并在需要时取消它们,文章还讨论了CancellationToken参数的重要性

Task任务的取消

c# 任务的取消,需要用到CancellationTokenSource类,CancellationToken结构体。

注意:CancellationTokenSource是class类型,而CancellationToken是struct结构体。

任务内部"监听"CancellationToken方法

任务的内部在合适的时候不停地调用CancellationToken的ThrowIfCancellationRequested()方法,这个函数会抛出一个叫做OperationCanceledException的异常,它的实现(微软开源代码)如下:

        public void ThrowIfCancellationRequested()
        {
            if (IsCancellationRequested) 
                ThrowOperationCanceledException();
        }

下面的列子通过Task.Run产生了一个任务。Task任务的内部正式通过抛出OperationCanceledException异常达到被取消的目的。而任务的外部则是通过调用CancellationTokenSource实例的Cancel()方法来触发取消的动作的。

下面的例子是一个取消Task任务的例子

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;
        var tokenSource3 = new CancellationTokenSource();

        var task = Task.Run(() =>
        {
            // Were we already canceled?
            ct.ThrowIfCancellationRequested();
            
            bool moreToDo = true;
            while (moreToDo)
            {
                // Poll on this property if you have to do
                // other cleanup before throwing.
                // Clean up here, then...
                if(ct.IsCancellationRequested)
                {
                    ct.ThrowIfCancellationRequested();
                }
            }
        },tokenSource2.Token); // Pass same token to Task.Run.

        Thread.Sleep(5000);
        tokenSource2.Cancel();

        // Just continue on this thread, or await with try-catch:
        try
        {
            await task;
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
            bool eqs = e.CancellationToken.Equals(tokenSource3.Token);
            System.Console.WriteLine($"Equals' result: {eqs}.");
            System.Console.WriteLine($"Task's status: {task.Status}");
        }
        catch (Exception ex)
        {
            System.Console.WriteLine(ex.Message);
        }
        finally
        {
            tokenSource2.Dispose();
        }

        Console.ReadKey();
    }
}
/*
The operation was canceled.
OperationCanceledException thrown with message: The operation was canceled.
Equals' result: False.
Task's status: Canceled
*/

这个例子中我们在Task的外部创建了2个CancellationTokenSource实例,因为CancellationTokenSource类包含一个CancellationToken类的属性Token,这也就意味着例子当中包含了两个CancellationToken实例。

ThrowIfCancellationRequested()方法会把调用它的CancellationToken实例也作为参数一起携带抛出。

因此catch块参数e中包含的是tokenSource2.Token,因此它与tokenSource3.Token进行相等比较输出一定是false。

又因为Task.Run()方法中传入的第二个参数也是tokenSource2.Token,Task核心框架内部会比较OperationCanceledException异常中携带的CancellationToken实例和Task.Run()方法中传入的CancellationToken实例,如果两者是一样的,则Task的status状态设为Canceled,表示成功取消;如果两者不一样,Task任务仍然会退出,但是Task的status状态设为Faulted,表示出错。

如果将第29行改为:

},tokenSource3.Token); // Pass same token to Task.Run.

则,结果输出如下:

OperationCanceledException thrown with message: The operation was canceled.
Equals' result: False.
Task's status: Faulted

看起来,Task任务也被取消了,但是实际上是由于出错而退出。因此,Task.Run的第二个参数可以用来确保内部实际引发取消异常的CancellationToken实例和Task.Run传入的CancellationToken实例要一致才能成功取消,否则框架会误认为你是误操作而导致退出的。因此,Task.Run的CancellationToken参数是为了更加安全。

如果将29行改为不带CancellationToken参数的重载函数,那么返回的也是一样的Faulted结果。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C#Url操作类封装、仿Node.Js中的Url模块实例

    C#Url操作类封装、仿Node.Js中的Url模块实例

    这篇文章主要介绍了C#Url操作类封装、仿Node.Js中的Url模块,实例分析了C#Url操作类封装的技巧,非常具有实用价值,需要的朋友可以参考下。
    2016-10-10
  • 在C#中List集合使用First()方法获取第一个元素的操作

    在C#中List集合使用First()方法获取第一个元素的操作

    这篇文章主要介绍了在C#中List集合使用First()方法获取第一个元素的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • C#实现简易灰度图和酷炫HeatMap热力图winform(附DEMO)

    C#实现简易灰度图和酷炫HeatMap热力图winform(附DEMO)

    本文主要介绍了C#实现简易灰度图和酷炫HeatMap热力图winform(附DEMO),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • C#实现PDF文件添加图片背景

    C#实现PDF文件添加图片背景

    这篇文章主要介绍了C#实现PDF文件添加图片背景的相关资料,需要的朋友可以参考下
    2016-02-02
  • C# 操作Windows注册表的实现方法

    C# 操作Windows注册表的实现方法

    本文主要介绍了C# 操作Windows注册表的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-03-03
  • C#中值类型和引用类型常见错误示例小结

    C#中值类型和引用类型常见错误示例小结

    本文总结了C#中值类型与引用类型常见错误,包括错误假设、未初始化、比较方式、数组操作、字符串处理及out/ref参数使用,具有一定的参考价值,感兴趣的可以了解一下
    2025-06-06
  • 浅谈熟悉C#如何转TypeScript

    浅谈熟悉C#如何转TypeScript

    本文主要介绍了浅谈熟悉C#如何转TypeScript,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-05-05
  • 利用C#验证哥德巴赫猜想的示例代码

    利用C#验证哥德巴赫猜想的示例代码

    哥德巴赫猜想(Goldbach’s Conjecture)是数学领域的一个著名猜想,大致内容为任何一个大于2的偶数都可以表示为两个质数之和,下面我们就来看看如何利用C#验证这一猜想呢
    2024-03-03
  • c#对XML文档的创建与增删改查的示例代码

    c#对XML文档的创建与增删改查的示例代码

    这篇文章主要介绍了c#对XML文档的创建与增删改查的示例代码,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • 解决WPF绘制矢量图形模糊的问题

    解决WPF绘制矢量图形模糊的问题

    这篇文章介绍了WPF绘制矢量图形模糊问题的解决方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06

最新评论