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结果。

总结

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

相关文章

  • Unity实现卡拉OK歌词过渡效果

    Unity实现卡拉OK歌词过渡效果

    这篇文章主要为大家详细介绍了Unity实现卡拉OK歌词过渡效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06
  • WPF实现html中的table控件的示例代码

    WPF实现html中的table控件的示例代码

    相信很多做WPF开发的小伙伴都遇到过表格类的需求,虽然现有的Grid控件也能实现,但是使用起来的体验感并不好,所以本文我们就来用WPF自己实现一个html中的table控件吧
    2024-03-03
  • Unity 修改FBX模型动画的操作

    Unity 修改FBX模型动画的操作

    这篇文章主要介绍了Unity 修改FBX模型动画的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • c# 网络编程之http

    c# 网络编程之http

    这篇文章主要介绍了c# 提供一个HTTP服务的实现示例,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下
    2021-02-02
  • C#实现微信公众号群发消息(解决一天只能发一次的限制)实例分享

    C#实现微信公众号群发消息(解决一天只能发一次的限制)实例分享

    经过几天研究网上的代码和谢灿大神的帮忙,今天终于用C#实现了微信公众号群发消息,现在分享一下
    2013-09-09
  • c# Winform自定义控件-仪表盘功能

    c# Winform自定义控件-仪表盘功能

    这篇文章主要介绍了c#Winform自定义控件-仪表盘功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • C#实现ComboBox控件显示出多个数据源属性的方法

    C#实现ComboBox控件显示出多个数据源属性的方法

    这篇文章主要介绍了C#实现ComboBox控件显示出多个数据源属性的方法,实例分析了ComboBox控件的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • string与stringbuilder两者的区别

    string与stringbuilder两者的区别

    今天小编就为大家分享一篇关于string与stringbuilder两者的区别,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • C#实现视频的批量剪辑功能

    C#实现视频的批量剪辑功能

    这篇文章主要介绍了C#实现视频的批量剪辑功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • C#可用于登录验证码的四位随机数生成方法

    C#可用于登录验证码的四位随机数生成方法

    这篇文章主要介绍了C#可用于登录验证码的四位随机数生成方法,提供了两种生成四位随机数的方法供大家参考,是非常实用的技巧,需要的朋友可以参考下
    2014-12-12

最新评论