【C#】Task 线程停止

CancellationTokenSource cts 是用于控制任务(线程)停止运行的。我们一步步来解释它的作用。


🔍 现在的代码结构大概是这样的:

Task.Run(() => {while (true){// 不断循环采集图像}
});

这种写法虽然简单,但最大的问题是:

  • 这个线程永远停不下来
  • 你无法在外部优雅地告诉它“嘿,停一下”,除非强行杀掉进程。

✅ 而 CancellationTokenSource 就是为了解决这个问题。

📌 它的作用:

提供一种机制,可以从外部请求取消正在运行的任务或线程


🧠 举个简单的例子

CancellationTokenSource cts = new CancellationTokenSource();Task.Run(() =>
{while (!cts.Token.IsCancellationRequested){Console.WriteLine("工作中...");Thread.Sleep(1000);}Console.WriteLine("收到取消信号,退出循环!");
});// 5秒后取消
Thread.Sleep(5000);
cts.Cancel();
输出:
工作中...
工作中...
工作中...
工作中...
工作中...
收到取消信号,退出循环!

🚦 实际在你的程序中,使用它的意义是:

  • 将来你关闭程序或点击“停止”按钮时,
  • 你只需调用 cts.Cancel()
  • 运行中的 while (!cts.Token.IsCancellationRequested) 就会安全退出。

🔁 没有它会发生什么?

如果你一直用 while (true),即使界面关闭、用户点击“停止”,后台线程仍然在跑,非常浪费资源,甚至会造成程序无法正常退出或 CPU 飙高。


✅ 总结一句话:

CancellationTokenSource 就像一个“遥控开关”,可以让后台线程知道“该停下来了”。


它和while中放个bool变量有啥区别

“在 while 中放一个 bool 变量”确实也是一种控制循环退出的方式,那它和 CancellationTokenSource 有什么区别呢?我们来做个对比👇


🆚 bool 控制变量 vs CancellationToken

对比项bool 控制变量CancellationTokenSource
基本功能控制循环停止控制循环停止
👨‍💻 用法简单非常简单(比如 while (running)稍复杂,需要 cts.Token 等对象
多任务控制需要共享变量或加锁天生就支持多个任务共享同一个 token
线程安全性需要你手动保证线程安全(如加 volatilelock自带线程安全,不容易出错
🔄 Task / async / Parallel 等配合兼容差,不好配合现代并发工具Task.RunParallel.ForEachasync/await 等无缝集成
💣 取消等待无法中断 Task.Delay / Wait可中断等待任务,比如 Task.Delay(..., token)
🎯 最佳应用场景简单循环退出复杂并发任务、任务取消、超时控制等

🔍 示例对比:

✅ 用 bool 控制变量:
volatile bool running = true;Task.Run(() =>
{while (running){// 采图}
});// 关闭时
running = false;

注意这里用了 volatile 是因为如果不写,可能在多线程中有缓存失效的问题(CPU 缓存没及时刷新变量值)。


✅ 用 CancellationToken
CancellationTokenSource cts = new CancellationTokenSource();Task.Run(() =>
{while (!cts.Token.IsCancellationRequested){// 采图}
});// 关闭时
cts.Cancel();

这样可以安全、优雅地中止线程,还可以用于 Task.DelayParallel.ForEachHttpClient.SendAsync 等现代 API。


深入探讨

逐条举例 + 拆解对比,让它变得通俗易懂且能立刻理解!


✅ 多任务控制(多线程共享控制)

🔸 bool 的写法:

你得写成这样👇

volatile bool _running = true;Task.Run(() =>
{while (_running){// 做事...}
});Task.Run(() =>
{while (_running){// 另一个线程做事...}
});
  • 如果多个任务要响应这个 bool,你得自己保证它是线程安全的(加 volatile),
  • 若再多几个线程,管理起来越来越麻烦。

CancellationToken 的写法(天然支持):

var cts = new CancellationTokenSource();
var token = cts.Token;Task.Run(() => Work(token));
Task.Run(() => Work(token));void Work(CancellationToken token)
{while (!token.IsCancellationRequested){// 干活...}
}

✅ 所有任务共用一个 token,控制统一、安全、优雅,代码看起来也很干净。


❌ 线程安全性

🔸 bool 写法:

必须加 volatilelock,否则有可能一个线程改了,另一个线程根本“看不见”:

volatile bool _running = true;// 不加 volatile,可能一个线程死循环都不会停

或者你得用 lock,比如:

lock (_lockObj)
{_running = false;
}

复杂且容易忘。


CancellationToken

  • 内部已经做好线程安全,不用你操心
  • .IsCancellationRequested 是线程安全的读操作
  • .Cancel() 会安全地广播给所有监听者

🔄 与 Task / async / Parallel 等配合

🔸 bool 写法:

比如你想写个 Task.Delay(5000),中途取消:

await Task.Delay(5000); // 没法中断!

你只能写复杂逻辑轮询 bool,还不能打断系统 API。


CancellationToken

await Task.Delay(5000, token); // 支持取消!

同样适用于:

  • Parallel.ForEach(..., token, ...)
  • HttpClient.SendAsync(..., token)
  • Task.Run(() => ..., token)

它和这些 现代异步/并发工具是“原生支持”的搭档


🧠 总结一句话:

bool 适合非常简单的控制,一两个线程内部用可以;但如果你要和 Task、多个线程、现代异步配合,CancellationToken 才是真正线程安全、优雅且可组合的现代解决方案。


✅ 建议

  • 简单项目、没用多线程/异步的地方bool 就够了。
  • 多线程、用 Taskasync/await、任务并发的项目 → 建议用 CancellationToken,更稳更现代。

如果你目前只是用一个线程干活,可以继续用 bool,但随着项目复杂度提升,CancellationToken 会更适合并发环境,特别是你这个多相机+高速采集的系统。以后维护、扩展也更舒服。

2025年3月29日---------------新增内容:

Task.Delay 的第二个参数不是 CancellationTokenSource,而是它里面的 CancellationToken


✅ 正确语法:

var cts = new CancellationTokenSource();
await Task.Delay(5000, cts.Token); // 注意这里是 cts.Token,不是 cts 本身

❓为什么不是 cts 本身?

  • CancellationTokenSource 是控制器:可以 .Cancel() 来通知取消。
  • CancellationToken 是“令牌”:传给任务或方法来监听是否被取消。
// 你控制取消:
cts.Cancel();// 你监听是否被取消:
token.IsCancellationRequested

就像你开会:

  • CancellationTokenSource 是主持人(可以宣布“散会!”)
  • CancellationToken 是给每个人的耳机(听到“散会”指令)

🚫 错误写法(会编译错误):

await Task.Delay(5000, cts); // ❌ 错!类型不匹配

✅ 正确写法:

await Task.Delay(5000, cts.Token); // ✅

cts.Cancel(); 之后,下次再次启动怎么办?

在调用 cts.Cancel(); 之后,CancellationTokenSource 不能被重用。如果你想要再次启动任务,需要创建一个新的 CancellationTokenSource 实例。


❌ 不能直接复用 CancellationTokenSource

cts.Cancel(); 调用后,cts.Token 状态不会被重置,即使你重新启动任务,它会立即认为任务已被取消。

✅ 解决方案:创建新的 CancellationTokenSource

每次启动新任务时,都需要创建一个新的 CancellationTokenSource

CancellationTokenSource cts = new CancellationTokenSource();void StartTask()
{cts = new CancellationTokenSource(); // 重新创建一个新的 ctsTask.Run(() =>{while (!cts.Token.IsCancellationRequested){Console.WriteLine("运行中...");Thread.Sleep(1000);}Console.WriteLine("循环退出");});
}// 启动任务
StartTask();// 运行 3 秒后取消
Thread.Sleep(3000);
cts.Cancel();
Console.WriteLine("任务已停止");// 等待一会儿,再次启动
Thread.Sleep(2000);
StartTask(); // ✅ 重新创建 cts,再次启动任务
Console.WriteLine("任务重新启动");

🔹 正确做法

  • 每次 StartTask() 都创建一个新的 CancellationTokenSource
  • 这样 cts.Token.IsCancellationRequested 重新变为 false,新任务不会立即退出。

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

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

相关文章

WebRTC的ICE之TURN协议的交互流程中继转发Relay媒体数据的turnserver的测试

WebRTC的ICE之TURN协议的交互流程和中继转发Relay媒体数据的turnserver的测试 WebRTC的ICE之TURN协议的交互流程中继转发Relay媒体数据的turnserver的测试 WebRTC的ICE之TURN协议的交互流程和中继转发Relay媒体数据的turnserver的测试前言一、TURN协议1、连接Turn Server 流程①…

Redis + Caffeine多级缓存电商场景深度解析

Redis Caffeine多级缓存 Redis Caffeine多级缓存电商场景深度解析一、实施目的二、具体实施2.1 架构设计2.2 组件配置2.3 核心代码实现 三、实施效果3.1 性能指标对比3.2 业务指标改善3.3 系统稳定性 四、关键策略4.1 缓存预热4.2 一致性保障4.3 监控配置Prometheus监控指标 …

前端开发3D-基于three.js

基于 three.js 渲染任何画面,都要基于这 3 个要素来实现 1场景scene:放置物体的容器 2摄像机:类似人眼,可调整位置,角度等信息,展示不同画面 3渲染器:接收场景和摄像机对象,计算在浏…

代码随想录算法训练营--打卡day4

一.移除链表元素 1.题目链接 203. 移除链表元素 - 力扣(LeetCode) 2.思路 通过 while 循环来遍历链表,只要 cur 的下一个节点不为空,就继续循环。在循环中,对 cur 的下一个节点的值进行判断: 值不等于…

虚拟电厂:多元能源聚合,开启绿色电力新时代

虚拟电厂:多元能源聚合,开启绿色电力新时代 在“双碳”目标驱动下,电力系统正经历从集中式向分布式、从单一能源向多能互补的深刻变革。 作为能源互联网的核心载体,虚拟电厂通过数字化技术整合多种能源资源,而是像指…

高通Android10 铃声通话音频80%音量修改

先修改最高的音量step --- a/SC60_AP/frameworks/base/services/core/java/com/android/server/audio/AudioService.javab/SC60_AP/frameworks/base/services/core/java/com/android/server/audio/AudioService.java-311,14 311,14 public class AudioService extends IAudio…

类加载过程?类隔离了解过吗?

类加载过程详解 类加载是 JVM 将类的字节码从磁盘、网络或其他来源加载到内存,并转换为 Class 对象的过程,主要分为以下 五个阶段: 1. 加载(Loading) 任务:查找类的二进制字节流(如 .class 文…

使用msmtp和mutt在CentOS上发送指定目录下的所有文件作为邮件附件

1.安装 msmtp: 如果尚未安装,请先通过以下命令安装msmtp。 sudo yum install msmtp 2.配置 msmtp 使用新浪邮箱: 创建或编辑配置文件~/.msmtprc,输入以下内容(记得替换授权码)。 defaults tls on tls_st…

Vue+Elementui首页看板

源码 <template><!-- 查询条件--><div class="optimize-norm" v-loading="selectDataLoading"><el-form :model="queryParams" ref="queryRef" style="padding-bottom:8px" :inline="true"…

汇编学习之《指针寄存器大小端学习》

什么是指针寄存器&#xff1f; 操作栈的寄存器 栈&#xff1a; 保存函数里面传递的参数&#xff0c;局部变量等。 EBP&#xff1a; 指向栈底的指针 ESP&#xff1a; 指向栈顶的指针。 计算入栈地址变化规则 通过OllDbg查看 有可能点击安装的时候栈区域第一次查看会没有显…

Oracle数据库数据编程SQL<3.7 PL/SQL 触发器(Trigger)>

触发器是Oracle数据库中的一种特殊存储过程&#xff0c;它会在特定数据库事件发生时自动执行。触发器通常用于实现复杂的业务规则、数据验证、审计跟踪等功能。 目录 一、触发器基本概念 1. 触发器特点 2. 触发器组成要素 二、触发器类型 1. DML触发器 2. DDL触发器 3.…

2025年渗透测试面试题总结-某 携程旅游-基础安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 携程旅游-基础安全工程师 反序列化原理 核心原理 扩展分析 SQL注入本质 核心原理 扩展分析 SQL注…

CSS 边框(Border)样式详解

CSS 边框&#xff08;Border&#xff09;样式详解 CSS 提供了多种边框样式&#xff0c;使我们能够控制元素的外观。本文将详细介绍 CSS 边框的各种属性及应用示例。 1. 基本边框属性 CSS 主要使用 border 相关属性定义边框&#xff0c;基本语法如下&#xff1a; border: [边…

SpringCould微服务架构之Docker(6)

容器的基本命令&#xff1a; 1. docker exec &#xff1a;进入容器执行命令 2. docker logs: -f 持续查看容器的运行日志 3. docker ps&#xff1a;查看所有运行的容器和状态 案例&#xff1a;创建运行一个容Nginx容器 docker run--name myNginx -p 80:80 -d nginx 命…

unity3d端监听 uri scheme

一、消息监听 1.创建一个脚本命名为 “URISchemeListener” &#xff0c;用于接收URI消息&#xff08;代码如下&#xff09;。 using System; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.UI;public class URISchemeListener : MonoBehavio…

网络信息安全应急演练方案

信息安全应急演练方案 总则 &#xff08;一&#xff09;编制目的 旨在建立并完善应对病毒入侵、Webshell 攻击以及未授权访问等信息安全突发事件的应急机制&#xff0c;提升组织对这类事件的快速响应、协同处理和恢复能力&#xff0c;最大程度降低事件对业务运营、数据安全和…

电商场景下高稳定性数据接口的选型与实践

在电商系统开发中&#xff0c;API接口需要应对高并发请求、动态数据更新和复杂业务场景。我将重点解析电商场景对数据接口的特殊需求及选型方案。 一、电商API必备的四大核心能力 千万级商品数据实时同步 支持SKU基础信息/价格/库存多维度更新每日增量数据抓取与历史版本对比…

Android R adb remount 调用流程

目的&#xff1a;调查adb remount 与adb shell进去后执行remount的差异 调试方法&#xff1a;添加log编译adbd,替换system\apex\com.android.adbd\bin\adbd 一、调查adb remount实现 关键代码&#xff1a;system\core\adb\daemon\services.cpp unique_fd daemon_service_to…

多模态大语言模型arxiv论文略读(二)

Identifying the Correlation Between Language Distance and Cross-Lingual Transfer in a Multilingual Representation Space ➡️ 论文标题&#xff1a;Identifying the Correlation Between Language Distance and Cross-Lingual Transfer in a Multilingual Representat…

【运维】负载均衡

老规矩&#xff0c;先占坑&#xff0c;后续更新。 开头先理解一下所谓的“均衡”&#xff0c;不能狭义地理解为分配给所有实际服务器一样多的工作量&#xff0c;因为多台服务器的承载能力各不相同&#xff0c;这可能体现在硬件配置、网络带宽的差异&#xff0c;也可能因为某台…