C# 取消一个不带CancellationToken的任务?

news2024/12/24 3:02:35

        在异步函数中,一般使用CancellationToken来控制函数的执行。这个Token需要作为参数传递到异步函数中:

public staic Task<T> DoAsync(CancellationToken token)
{
    ...
}

        那么如果一个异步函数没有这个Token参数,如何取消呢?

        之前看到一个博客:How to Cancel a Non-Cancellable Task in C#


1.构建取消异步函数的扩展方法

        先上代码:

    public static class TaskExtensions
    {
        public static async Task<T> WithCancellation<T> (this Task<T> task,CancellationToken cancellationToken)
        {
            var tcs=new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
            using (cancellationToken.Register(state =>
            {
                ((TaskCompletionSource<object>)state!).TrySetResult(null!);
            }, tcs))
            {
                var resultTask = await Task.WhenAny(task, tcs.Task);
                if(resultTask==tcs.Task)
                {
                    throw new OperationCanceledException(cancellationToken);
                }
                return await task;
            }
        }
    }

        显然这是一个扩展方法,旨在为Task<T>类型扩展一个名叫WithCancellation函数。这个函数会有一个CancellationToken,但这个Token不是传递给任务参数task(也就是我们要取消的函数)的,而是用于外部控制。

        代码中首先构建了一个异步任务,利用TaskCompletionSource<T>,可以构建一个用于控制原任务的异步任务,这里的TaskCompletionSource不多解释了,可以参考博客:here。然后通过传入的Token注册一个回调函数,回调函数传入的参数就是刚刚创立的TaskCompletionSource<T>对象,回调函数会调用成员函数TrySetResult()给任务赋值。而回调函数的执行则是在Token被取消时触发。

2. 测试

        然后我们使用这个扩展方法构建实例:

 internal class CancelTaskWithoutCancellationToken
    {
        private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

        public static async Task Test()
        {
            try
            {
                var result = await Task.Run(async () =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(5));
                    Console.WriteLine("操作完成");
                    await Task.Delay(300);
                    Console.WriteLine("还继续吗?");
                    return 7;
                }).WithCancellation(cancellationTokenSource.Token);
                Console.WriteLine(result.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("任务取消了");
            }
            finally
            {
                cancellationTokenSource.Dispose();
            }
        }
        public static void Cancel()
        {
            cancellationTokenSource?.Cancel();
        }
    }

测试代码:

var t1=CancelTaskWithoutCancellationToken.Test();
var t2 = Task.Run(() =>
{
    Thread.Sleep(1000);
    CancelTaskWithoutCancellationToken.Cancel();
});
await Task.WhenAll(t1, t2);

运行结果如下:

好像结果很符合预期。

假设测试代码后面还有一些任务要运行,也就是主线程没那么快结束呢?让我们在测试代码后面加一行:

var t1=CancelTaskWithoutCancellationToken.Test();
var t2 = Task.Run(() =>
{
    Thread.Sleep(1000);
    CancelTaskWithoutCancellationToken.Cancel();
});
await Task.WhenAll(t1, t2);
Console.WriteLine("----------------------");
Console.ReadLine();

运行结果:

        Oh No,原来的任务还是执行了,说明没能阻止那个任务继续运行,所以原博客说取消一个不能被取消的任务(non-cancelable)是错的,开工没有回头箭。但是从前面的例子,我们可以取消等待那个任务。

        实际上博主在另外一篇博客找到了关于这个问题的说明:

 How do I cancel non-cancelable async operations?

        博主在最后总结:

So, can you cancel non-cancelable operations? No.  Can you cancel waits on non-cancelable operations?  Sure… just be very careful when you do.

        所以,如果想能随时取消一个Task,最稳妥的办法还是将Token作为参数传递进去

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1106313.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Upload-labs(1-20关保姆级教程)

靶场下载链接 https://github.com/c0ny1/upload-labs 话不多说&#xff0c;直接喂饭 lab-1 上传php木马&#xff0c;发现弹出提示框&#xff0c;查看源码可知是前端过滤&#xff1a; bp抓包&#xff0c;先上传一张正常的jpg图片 修改文件内容和后缀&#xff0c;大概就是想…

python栈和队列

python栈和队列 一、栈1. 栈的基本介绍2. 代码3. 基本操作4. 括号匹配问题5. 删除字符串所有相邻的重复项6. 出栈顺序是否合法 二、队列1. 队列基本介绍2. 队列代码3. 队列基本操作4. 约瑟夫环-循环嵌套5. 约瑟夫环-队列16. 约瑟夫环-队列2 一、栈 1. 栈的基本介绍 特点&…

接口测试经验合集

一 、接口测试常见问题 前景提要&#xff1a;由于本人测试小白&#xff0c;可能所遇问题都较为基础&#xff0c;测试小白可以参考 1.1 postman会报 connect ECONNREFUSED jemeter会报 org.apache.http.conn.HttpHostConnectException: Connect tofailed: Connection refus…

ASEMI-GBJ5010电源控制柜所用整流桥

编辑-Z 电源控制柜是一种常用的电力设备&#xff0c;广泛应用于工业生产过程中。在电源控制柜中&#xff0c;整流桥起着重要的作用。 整流桥是一种用于变流的电器元件&#xff0c;由4个二极管组成。它能够将交流电转换为直流电&#xff0c;并提供稳定的电源给控制柜中的其他设…

07 创建型模式-单例模式

1.单例模式介绍 单例模式&#xff08;Singleton Pattern&#xff09;是 Java 中最简单的设计模式之一&#xff0c;此模式保证 某个类在运行期间&#xff0c;只有一个实例对外提供服务&#xff0c;而这个类被称为单例类。 2.使用单例模式要做的两件事 保证一个类只有一个实例…

C语言实现:有 5 个人坐在一起,问第 5 个人多少岁?

完整代码&#xff1a; /*有 5 个人坐在一起&#xff0c;问第 5 个人多少岁?他说比第 4 个人大两岁。间第 4 个人岁 数&#xff0c;他说比第 3 个人大两岁。问第 3 个人&#xff0c;又说比第 2 个人大两岁。问第 2 个人&#xff0c; 说比第 1 个人大两岁。最后问第 1 个人&…

Linux内核驱动开发:技能、应用和挑战

Linux内核驱动开发&#xff1a;技能、应用和挑战 Linux内核驱动开发所需技能包括C语言和汇编语言编程、Linux系统编程接口、内核原理和机制、设备驱动开发和调试技术等。同时&#xff0c;熟悉常用的开发环境和工具如GNU工具链、make、gcc、gdb等也是必要的。 Linux内核驱动开…

在华为和比亚迪干了5年测试,月薪25K,熬夜总结出来的划水经验.....

先简单交代一下背景吧&#xff0c;某不知名 985 的本硕&#xff0c;17 年毕业加入华为&#xff0c;之后跳槽到了比亚迪&#xff0c;一直从事软件测试的工作。之前没有实习经历&#xff0c;算是5年的工作经验吧。 这5年之间完成了一次晋升&#xff0c;换了一家公司&#xff0c;…

scada组态软件和硬件结构的主要功能

scada在工厂自动化领域有许多应用。在行业内&#xff0c;所有现场仪表都单独连接到接线盒。多对电缆将从接线盒连接到控制室。 在scada中&#xff0c;电缆被接收在编组柜中。这里&#xff0c;电缆分为模拟输入&#xff08;AI&#xff09;、模拟输出&#xff08;AO&#xff09;…

3D视觉基础

3D 视觉领域是计算机视觉的一个重要分支&#xff0c;旨在模拟和分析三维空间中的物体、场景和运动。它结合了图像处理、计算几何学、机器学习和深度学习等技术&#xff0c;以从二维图像或传感器数据中重建三维信息。本文主要介绍 3D 视觉中的一些基础概念。 目录 一. 三维坐标系…

Datawhale学习笔记AI +新能源:电动汽车充电站充电量预测

赛题介绍 建立站点充电量预测模型&#xff0c;根据充电站的相关信息和历史电量数据&#xff0c;准确预测未来某段时间内充电站的充电量需求。 在赛题数据中&#xff0c;我们提供了电动汽车充电站的场站编号、位置信息、历史电量等基本信息。我们鼓励参赛选手在已有数据的基础上…

【C++初阶】引用内联函数auto关键字范围for循环nullptr

个人主页还有更多系列专栏&#xff1a;小白不是程序媛 我的小仓库&#xff1a;Gitee C系列专栏&#xff1a;C头疼记 目录 前言 引用 概念 引用的特点 常引用 引用的使用场景 做参数 做返回值 引用和指针的区别 引用和指针的不同点&#xff1a; 内联函数 内联函数…

【LeetCode刷题(数据结构与算法)】:二叉搜索树的范围和

一、什么是二叉搜索树 二叉搜索树&#xff08;BST&#xff0c;Binary Search Tree&#xff09;&#xff0c;也称二叉排序树或二叉查找树 二叉搜索树&#xff1a;一棵二叉树&#xff0c;可以为空&#xff1b;如果不为空&#xff0c;满足以下性质 非空左子树的所有键值小于其根结…

Typora使用教程

相关介绍 Typora是一款所写即所得的Markdown编辑器&#xff0c;支持跨平台Window,Linux和Mac都可以。 相关链接 Typora安装包历史版本地址&#xff1a;官网历史版本地址 问题及知识点汇总 关于图片的问题-设置图像自动复制到自己指定文件夹下 问题描述 在写笔记的过程中&am…

Write-Ahead Log(PostgreSQL 14 Internals翻译版)

日志 如果发生停电、操作系统错误或数据库服务器崩溃等故障&#xff0c;RAM中的所有内容都将丢失&#xff1b;只有写入磁盘的数据才会被保留。要在故障后启动服务器&#xff0c;必须恢复数据一致性。如果磁盘本身已损坏&#xff0c;则必须通过备份恢复来解决相同的问题。 理论…

C++ 类和对象(上)------超详细解析,小白必看系列

目录 一、前言 二、面向过程和面向对象初步认识 三、类的引入 三、类的定义 四、类的访问限定符及封装 &#x1f4a6;访问限定符 &#xff08;重点&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; &#x1f4a6;封装 五、类的作用域 六、类的实例化 …

算法--排序算法效率比较

《算法设计与分析》课程实验报告 &#xff08; 实验一&#xff09; 实验名称&#xff1a;排序算法效率比较 实验地点&#xff1a; 所使用的开发工具及环境&#xff1a; PC机&#xff0c;DEV 一、实验目的&#xff1a; 比较至少 4 种排序&#xff08;从小到大排&#xff09…

从十月稻田,看大米为何能卖出200亿市值?

国无农不稳&#xff0c;民无粮不安。新时代的农村农民&#xff0c;需要现代化的农业作依托&#xff0c;而在农业现代化的过程中&#xff0c;品牌化、数字化成为至关重要的一环。 金秋十月&#xff0c;从南到北&#xff0c;从东到西&#xff0c;中国农村的每一块土地都洋溢着丰…

【运筹优化】运筹学导论:线性规划导论

文章目录 一、原形范例&#xff08;Wyndor Glass 公司&#xff09;1.1 线性规划模型构建1.2 图解法1.3 结论 二、线性规划模型2.1 线性规划模型的标准形式2.2 其他形式2.3 模型解的术语 三、有关线性规划的假设3.1 比例性3.2 可加性3.3 可分割性3.4 确定性 四、补充例子4.1 放射…

ant的basedir内置属性

basedir是ant的内置属性&#xff0c;代表项目基础路径的绝对路径。它的默认值等于build文件的父目录。当然&#xff0c;可以通过project 的basedir 属性、或者单独的basedir 属性来覆盖。 例如&#xff0c;在工程的根目录下有个build.xml文件&#xff1a; build.xml文件的内…