我让DeepSeek帮我写了一段使用 CancellationTokenSource 取消任务的简单示例如下:

取消任务的简单示例
using System.Threading.Tasks;
using System.Threading; public async Task Test()
{
var cts = new CancellationTokenSource();
var task = Task.Run(() =>
{
while (true)
{
cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(200);
}
});
await Task.Delay(1000);
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
// task is cancelled
}
finally
{
cts.Dispose();
}
}

相对于不可取消的普通任务多了很多代码,并且终止任务的方式 ThrowIfCancellationRequested 内部是通过抛出异常实现的

ThrowIfCancellationRequested 内部代码
public void ThrowIfCancellationRequested()
{
if (IsCancellationRequested)
{
throw new OperationCanceledExceptionEx(this);
}
}

于是我就想自己封装一个简单的包装类,代码如下:

CancelableTask
namespace System.Threading.Tasks
{
public sealed class CancelableTask : Task
{
readonly object cancelLock = new object();
CancellationTokenSource cts; public bool IsCancellationRequested => cts != null && cts.IsCancellationRequested; private CancelableTask(Action action, CancellationToken token) : base(action, token) { } protected override void Dispose(bool disposing)
{
if (disposing)
{
cts?.Dispose();
}
base.Dispose(disposing);
} public void Cancel()
{
lock (cancelLock)
{
if (!IsCompleted && !IsCancellationRequested)
{
cts.Cancel();
}
}
} public static CancelableTask StartNew(Action action)
{
var cts = new CancellationTokenSource();
var task = new CancelableTask(action, cts.Token);
task.cts = cts;
task.Start();
return task;
} public static void Restart(ref CancelableTask task, Action action)
{
var oldTask = Interlocked.Exchange(ref task, null);
oldTask?.Cancel();
var newTask = StartNew(action);
Interlocked.Exchange(ref task, newTask);
}
}
}

此类公开了 Cancel 用来取消任务,静态的 StartNew 用来创建新实例,以及静态的 Restart 用来取消上个任务并重启任务,

还公开了一个 IsCancellationRequested 属性用来获取是否请求过取消任务,相对于调用 ThrowIfCancellationRequested 抛出异常来终止任务的方式性能更好也更加友好

使用此类重新编写上面的示例就简单很多了

CancelableTask 使用示例
using System.Threading.Tasks;

CancelableTask task;

public async Task Test()
{
task = CancelableTask.StartNew(() =>
{
while (!task.IsCancellationRequested)
{
Thread.Sleep(200);
}
});
await Task.Delay(1000);
task.Cancel();
await task;
}

C# Task 取消执行的简单封装的更多相关文章

  1. Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池

    前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...

  2. axios简单封装

    写在最前面 新手前端刚刚接触vue,感觉真的好用.项目中需要使用axios,然后学习了一下.借鉴网上一些大佬的经验,现在分享一下axios的简单封装,如果有什么错误的地方,请大家指出. axios安装 ...

  3. FMDB简单封装和使用

    工具:火狐浏览器+SQLite Manager插件 ; Xcode; FMDB库; 效果: 项目地址: https://github.com/sven713/PackFMDB 主要参考这两篇博客: 1 ...

  4. Android--Retrofit+RxJava的简单封装(三)

    1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下 先创建一个HttpMethods类,将Ret ...

  5. okhttp3 get post 简单封装

    最近打算在新项目中使用 okhttp3, 简单封装了一下异步 get post 因为 CallBack 也是在子线程中执行,所以用到了 Handler public class MyOkHttpCli ...

  6. 对pymysql的简单封装

    #coding=utf-8 #!/usr/bin/python import pymysql class MYSQL: """ 对pymysql的简单封装 "& ...

  7. MySQL的C++简单封装

    /* *介绍:MySQL的简单封装,支持流操作输入输出MySQL语句,然而并没有什么软用,大二学生自娱自乐,有不足求指点 *作者:MrEO *日期:2016.3.26 */ 头文件 my_sql.h ...

  8. redis数据库操作的C++简单封装

    用c++简单封装了redis的基本操作(hiredis) 接口包括:①链接和断开连接.②设置键值对(set).③查询键值对(get).④删除键值对(del).⑤将所有键显示出来 若任何一处发生错误,返 ...

  9. DBUtils-对JDBC简单封装的开源工具类库

    DBUtils 是对JDBC简单封装的开源工具类 详细介绍地址:  https://baike.baidu.com/item/Dbutils/10655914?fr=aladdin 在使用DBUtil ...

  10. Google图片加载库Glide的简单封装GlideUtils

    Google图片加载库Glide的简单封装GlideUtils 因为项目里用的Glide的地方比较多,所有简单的封装了以下,其实也没什么,就是写了个工具类,但是还是要把基础说下 Glide的Githu ...

随机推荐

  1. labelImg 工具介绍

    1.什么是labelImg 图片标记工具,生成的xml文件用于人工智能数据 2.怎么使用 打开图片文件夹 使用默认工具tooth 选中图片,快捷键w ,鼠标标记图片 [Ctrl+s] 保存

  2. Oracle客户端中文显示问号乱码问题

    Oracle显示中文显示??乱码 问题如下图 解决方法 打开Oracle客户端,新建一个SQL Window 输入select userenv('language') from dual 复制搜索到的 ...

  3. java真是一门丑陋的语言,我都new Thread.run了然后你告诉我是在当前线程中运行

    new Thread(x->{}).run(); 上方代码怎么看都应该是要开启新线程的,毕竟都已经new了.但是上方代码居然是在当前线程中运行!想要开启新线程得用.start()方法,如下: n ...

  4. composer init

    $ composer init Do not run Composer as root/super user! See https://getcomposer.org/root for details ...

  5. nginx下增加https端口的方法

    一.进入根目录我是使用xshell进行远程连接服务器的,连接到服务器首先输入cd /进入到根目录在这里插入图片描述二.配置nginx.conf文件首先输入cd etc/nginx进入到nginx目录在 ...

  6. 在Unity中实现(纯C#)热更新--使用ILRunTime{学习日志}

    热更新的逻辑:热更新的那部分内容其实就是一个dll的库文件,到时候修改也是改这个库文件: 我们只需要在主工程(我们的Unity项目)中引入并调用这个dll库里的代码就行了. 首先我们需要在Unity中 ...

  7. Nginx 301永久性转移

    我有个域名www.taadis.com, 想永久性转移到taadis.com. 前言 看到很多网友的做法是把taadis.com & www.taadis.com等多个域名放到一个server ...

  8. DeepseekScanner deepseek+python实现代码审计实战

    一.功能概述 DeepseekScanner实现了扫描源代码项目中的所有代码文件发送给deepseek进行安全审计的功能.具体细节包括扫描所有子目录中的代码文件,然后依次将代码文件切片发送到deeps ...

  9. JMeter递增加压总结

    1.安装插件 a.下载JMeterPlugins-Standard.jar文件 下载链接:https://jmeter-plugins.org/downloads/old/ 下载完成后解压,将JMet ...

  10. 编译nwjs/node-webkit可用的sqlite3简单靠谱的解决方案/在nwjs里使用sqlite

    大胸弟,如果你和我一样把官方给的方法和网上的文章都试过了还是编译不过,但又必须在nwjs里使用sqlite数据库,那么请继续往下看. 我的解决方法就是: 1.不编译 来吧,拥抱html5吧,具体来说就 ...