【C#】CancellationTokenSource 为任务或线程提供一种优雅的方式来支持取消操作

CancellationTokenSource 是 .NET 中用于管理任务或异步操作的取消机制的一个核心类。


核心功能

  1. 生成取消令牌 (CancellationToken)

    • CancellationTokenSource 是一个令牌的生产者,用来创建和管理 CancellationToken
    • CancellationToken 是取消机制的消费者,可以被传递到任务或异步操作中,通知它们“该停止了”。
  2. 触发取消

    • 调用 CancellationTokenSource.Cancel() 可以触发所有使用该令牌的任务或线程的取消操作。
  3. 取消协作

    • 它是 协作取消 的基础:任务或线程本身检查令牌状态并决定何时停止,而不是被强制终止。

使用场景

CancellationTokenSourceCancellationToken 常见于以下场景:

  • 异步任务 (async/await) 的取消。
  • 多线程任务的优雅停止。
  • 可控的长时间运行操作,比如轮询或计算。

类的主要成员

  1. 属性

    • Token: 获取与当前 CancellationTokenSource 关联的 CancellationToken
      CancellationToken token = cancellationTokenSource.Token;
      
    • IsCancellationRequested: 检查取消是否已经被请求。
      if (cancellationTokenSource.Token.IsCancellationRequested) {// Handle cancellation
      }
      
  2. 方法

    • Cancel(): 触发取消令牌。
      cancellationTokenSource.Cancel();
      
    • Dispose(): 释放 CancellationTokenSource 所使用的资源。
      cancellationTokenSource.Dispose();
      

简单工作原理

  1. 创建一个取消源:

    CancellationTokenSource cts = new CancellationTokenSource();
    
  2. 获取令牌并传递给任务:

    CancellationToken token = cts.Token;
    
  3. 任务中检查令牌:

    • 周期性地检查令牌的 IsCancellationRequested 属性。
    • 或直接调用 token.ThrowIfCancellationRequested() 抛出 OperationCanceledException
  4. 请求取消:

    cts.Cancel();
    

** 示例1 **

using System;
using System.Threading;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){CancellationTokenSource cts = new CancellationTokenSource();Task task = Task.Run(() => DoWork(cts.Token), cts.Token);Console.WriteLine("Press any key to cancel...");Console.ReadKey();cts.Cancel();try{await task;}catch (OperationCanceledException){Console.WriteLine("Task was cancelled.");}finally{cts.Dispose();}}static void DoWork(CancellationToken token){for (int i = 0; i < 10; i++){if (token.IsCancellationRequested){Console.WriteLine("Cancellation requested.");token.ThrowIfCancellationRequested(); // Gracefully exit.}Console.WriteLine($"Working {i}...");Thread.Sleep(1000); // Simulate work}}
}

示例中的流程

  1. 主线程创建 CancellationTokenSource
  2. 主线程启动任务,并将 CancellationToken 传递给任务。
  3. 任务定期检查 token.IsCancellationRequested 或使用 ThrowIfCancellationRequested()
  4. 用户按下键触发 cts.Cancel(),任务收到取消信号并安全退出。

** 示例2 **

private CancellationTokenSource CancellingReadingRecordTokenSource;
private bool _isReadingRecord = false;private async  void btnReadWaring_Click(object sender, EventArgs e){if (_isReadingRecord){MessageBox.Show("_ ReadingRecord is already running.");return;}_isReadingRecord = true;CancellingReadingRecordTokenSource = new CancellationTokenSource();try{await Task.Run(() => ReadingRecordLoop(CancellingReadingRecordTokenSource.Token));}catch (OperationCanceledException){// Handle cancellation gracefully if needed}finally{_isReadingRecord = false;}}private void ReadingRecordLoop(CancellationToken cancellationToken){while (!cancellationToken.IsCancellationRequested){string tmpStrRead = Common.mServoApi.dosomething();UpdateAlarmRecordResult(tmpStrRead);Thread.Sleep(50);  }}private void UpdateAlarmRecordResult(string result){if (edtUpdateResult.InvokeRequired){edtUpdateResult.Invoke(new Action(() => edtResult.Text = result));}else{edtUpdateResult.Text = result;}}private void btnStopReadWaring_Click(object sender, EventArgs e){if (_isReadingRecord){CancellingReadingRecordTokenSource?.Cancel();}}

补充 edtUpdateResult.InvokeRequired

这段代码的作用是确保跨线程访问控件时的线程安全性。在 Windows Forms 应用程序中,只有创建控件的线程(通常是主 UI 线程)可以直接操作该控件。如果尝试从其他线程访问或更新控件,程序可能会抛出异常。

核心概念
  1. InvokeRequired 属性

    • 检查当前线程是否是控件所属的 UI 线程。
    • 如果访问控件的线程不是创建它的线程,则返回 true
    • 常见于多线程环境中,比如任务 (Task)、线程 (Thread) 或异步操作中。
  2. Invoke 方法

    • 将操作委托给控件的创建线程执行。
    • 通过 Invoke 调用操作,确保代码在控件的 UI 线程上运行,避免线程安全问题。
  3. Action 委托

    • 这里使用了匿名方法(()=>{})作为 Action 委托。
    • Action 是一种无返回值的委托,用于包装控件更新的代码。 【值得展开讲】
  4. 为什么 ?

    • 如果不通过 Invoke 方法直接在非 UI 线程上更新控件,程序会抛出 InvalidOperationException,因为控件只能由其创建线程访问。

1. 检查是否需要 Invoke
if (edtUpdateMonitorResult.InvokeRequired)
  • 检查调用该代码的线程是否与创建 edtUpdateMonitorResult 的线程不同。
  • 如果不同,返回 true,表示需要通过 Invoke 进行线程安全的调用。
2. 使用 Invoke 更新控件
edtUpdateMonitorResult.Invoke(new Action(() => edtGetAllParamResult.Text = result));
  • 如果 InvokeRequiredtrue,则调用 Invoke
  • 通过 Action 委托,定义要执行的代码:
    () => edtGetAllParamResult.Text = result;
    
    • 这是一个 lambda 表达式,表示设置控件 edtGetAllParamResult.Text 的值为 result
  • 这段代码会被“转移”到创建控件的线程上安全执行。
3. 如果 InvokeRequiredfalse
  • 如果当前线程已经是 UI 线程,则无需使用 Invoke,直接执行控件的更新操作即可。

为什么只在 UI 控件中需要?

  • Windows Forms 的线程模型

    • 控件的底层依赖于 Win32 消息循环(Message Loop)。
    • 每个控件都有一个与之关联的线程,通常是主线程。
    • 为了避免线程冲突,只有创建控件的线程可以直接操作它。
  • 典型问题场景

    • 使用后台线程(如 ThreadTask)执行耗时操作,并尝试直接更新 UI 控件时,会导致异常。

适用场景

  1. 从后台线程更新 UI

    • 在异步任务中,获取数据并更新控件。
    • 如监控线程中周期性读取串口数据并更新文本框。
  2. 线程安全的控件访问

    • 确保跨线程操作控件时不会导致冲突。

小结

这段代码的主要目的是保证线程安全的控件更新:

  • InvokeRequired 检查是否需要切换到 UI 线程。
  • Invoke 把任务委托到控件的 UI 线程执行。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS API for Javascript学习

一、ArcGIS API for Javascript 介绍 ArcGIS API for Javascript 是由美国 Esri 公司推出&#xff0c;跟随ArcGIS 9.3 同时发布的&#xff0c;是Esri 基于dojo 框架和 REST 风格实现的一套编程接口。通过 ArcGIS API for Javascript可以对ArcGIS for Server 进行访问&#xff…

React表单联动

Ant Design 1、dependencies Form.Item 可以通过 dependencies 属性&#xff0c;设置关联字段。当关联字段的值发生变化时&#xff0c;会触发校验与更新。 一种常见的场景&#xff1a;注册用户表单的“密码”与“确认密码”字段。“确认密码”校验依赖于“密码”字段&#x…

Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序

在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序 IntelliJ IDEA 是一个用 Java 编写的集成开发环境 (IDE)。它用于开发计算机软件。此 IDE 由 Jetbrains 开发&#xff0c;提供 Apache 2 许可社区版和商业版。它是一种智能的上下文感知 IDE&#xff0c;可用于在各种应用程序…

丹摩征文活动|实现Llama3.1大模型的本地部署

文章目录 1.前言2.丹摩的配置3.Llama3.1的本地配置4. 最终界面 丹摩 1.前言 Llama3.1是Meta 公司发布的最新开源大型语言模型&#xff0c;相较于之前的版本&#xff0c;它在规模和功能上实现了显著提升&#xff0c;尤其是最大的 4050亿参数版本&#xff0c;成为开源社区中非常…

STM32F103外部中断配置

一、外部中断 在上一节我们介绍了STM32f103的嵌套向量中断控制器&#xff0c;其中包括中断的使能、失能、中断优先级分组以及中断优先级配置等内容。 1.1 外部中断/事件控制器 在STM32f103支持的60个可屏蔽中断中&#xff0c;有一些比较特殊的中断&#xff1a; 中断编号13 EXTI…

docker run m3e 配置网络,自动重启,GPU等 配置渠道要点

启动命令&#xff1a; docker run -d --restart always -p 6008:6008 --gpus all --name m3e --network fastgpt_fastgpt stawky/m3e-large-api 配置渠道m3e base url要像我这样填写才行&#xff0c;不然回出问题 模型要选m3e 密钥填&#xff1a;sk-aaabbbcccdddeeefffggghhhi…

ubuntu24挂载硬盘记录

1、显示硬盘及所属分区情况。在终端窗口中输入如下命令&#xff1a; sudo fdisk -l 找到自己硬盘的分区 我的地址/dev/sda 2、显示硬盘及所属分区情况。在终端窗口中输入如下命令&#xff0c;格式化自己硬盘&#xff1a; sudo mkfs -t ext4 /dev/sda 3、在终端窗口中输入如下…

加菲工具 - 好用免费的在线工具集合

加菲工具 https://orcc.online AI 工具 加菲工具 集合了目前主流的&#xff0c;免费可用的ai工具 文档处理 加菲工具 pdf转word、office与pdf互转等等工具都有链接 图片图标 加菲工具 统计了好用免费的在线工具 编码解码 加菲工具 base64编码解码、url编码解码、md5计算…

网络安全与加密

1.Base64简单说明描述&#xff1a;Base64可以成为密码学的基石&#xff0c;非常重要。特点&#xff1a;可以将任意的二进制数据进行Base64编码结果&#xff1a;所有的数据都能被编码为并只用65个字符就能表示的文本文件。65字符&#xff1a;A~Z a~z 0~9 / 对文件进行base64编码…

Easyexcel(6-单元格合并)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09;Easyexcel&#xff08;6-单…

三种蓝牙架构实现方案

一、蓝牙架构方案 1、hostcontroller双芯片标准架构 手机里面包含很多SoC或者模块&#xff0c;每颗SoC或者模块都有自己独有的功能&#xff0c;比如手机应用跑在AP芯片上&#xff0c;显示屏&#xff0c;3G/4G通信&#xff0c;WiFi/蓝牙等都有自己专门的SoC或者模块&#xff0…

docker 容器运行Ruoyi-cloud

目录 1&#xff0c;linux系统安装openjdk1.8,mvn,dokcer,node,git 2&#xff0c;拉取代码 1&#xff09;查看gitee仓库地址 2&#xff09;创建/app文件夹&#xff0c;进入app目录 3&#xff09;clone代码 4&#xff09;修改配置文件中nacos地址 3&#xff0c;构建项目 1&…

QT简易项目 数据库可视化界面 数据库编程SQLITE QT5.12.3环境 C++实现

案例需求&#xff1a; 完成数据库插入&#xff0c;删除&#xff0c;修改&#xff0c;查看操作。 分为 插入&#xff0c;删除&#xff0c;修改&#xff0c;查看&#xff0c;查询 几个模块。 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget…

刷题——字符串中的单词数(力扣)

文章目录 一、读题二、思路问题1&#xff1a;解决思路&#xff1a;分割方法&#xff1a;方法1、方法2、 三、代码实现&#xff1a;方法1、方法2、 一、读题 题目来源&#xff1a;https://leetcode.cn/problems/number-of-segments-in-a-string/description/ 首先看例子&#xf…

【人工智能】PyTorch、TensorFlow 和 Keras 全面解析与对比:深度学习框架的终极指南

文章目录 PyTorch 全面解析2.1 PyTorch 的发展历程2.2 PyTorch 的核心特点2.3 PyTorch 的应用场景 TensorFlow 全面解析3.1 TensorFlow 的发展历程3.2 TensorFlow 的核心特点3.3 TensorFlow 的应用场景 Keras 全面解析4.1 Keras 的发展历程4.2 Keras 的核心特点4.3 Keras 的应用…

什么是 WPF 中的依赖属性?有什么作用?

依赖属性&#xff08;Dependency Property&#xff09;是 WPF 的一个核心概念&#xff0c;它为传统的 .NET 属性提供了增强功能&#xff0c;支持绑定、样式、动画和默认值等功能。通过依赖属性&#xff0c;WPF 提供了一种灵活的数据驱动的方式来处理 UI 属性。 1. 什么是依赖属…

在win10环境部署opengauss数据库(包含各种可能遇到的问题解决)

适用于windows环境下通过docker desktop实现opengauss部署&#xff0c;请审题。 文章目录 前言一、部署适合deskdocker的环境二、安装opengauss数据库1.配置docker镜像源2.拉取镜像源 总结 前言 注意事项&#xff1a;后面docker拉取镜像源最好电脑有科学上网工具如果没有科学上…

2024年11月25日Github流行趋势

项目名称&#xff1a;flux 项目维护者&#xff1a;timudk jenuk apolinario zeke thibautRe项目介绍&#xff1a;FLUX.1模型的官方推理仓库。项目star数&#xff1a;17,381项目fork数&#xff1a;1,229 项目名称&#xff1a;screenshot-to-code 项目维护者&#xff1a;abi cle…

Python 爬虫从入门到(不)入狱学习笔记

爬虫的流程&#xff1a;从入门到入狱 1 获取网页内容1.1 发送 HTTP 请求1.2 Python 的 Requests 库1.2 实战&#xff1a;豆瓣电影 scrape_douban.py 2 解析网页内容2.1 HTML 网页结构2.2 Python 的 Beautiful Soup 库 3 存储或分析数据&#xff08;略&#xff09; 一般爬虫的基…

Linux麦克风录音实战

在 Linux 上使用麦克风进行录音可以通过多种方式实现&#xff0c;包括使用命令行工具、图形界面应用程序以及编程接口。下面我将介绍几种常见的方法&#xff0c;从简单的命令行工具到使用 PortAudio 库进行编程。 一. 使用arecord命令行工具 arecord 是 ALSA&#xff08;Adva…