【C#】Task 线程停止

ops/2025/4/1 3:20:34/

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); // ✅

http://www.ppmy.cn/ops/170752.html

相关文章

Go语言和前端的DES加密解密

Go语言和前端的DES加密解密 前端实现 安装加密包 npm install crypto-js封装加密 des.js import CryptoJS from ../node_modules/crypto-js/crypto-js.js // DES加密 export const encryptDes (message, key) > {const keyHex CryptoJS.enc.Utf8.parse(key);const en…

Python爬虫实战:批量获取中国知网(CNKI)文献摘要教程

前言 本教程将详细介绍如何使用Python爬虫批量获取中国知网(CNKI)的文献摘要信息。即使你是编程新手,也能通过本教程快速掌握相关技能。教程包含完整源码和详细解释,助你轻松入门网络爬虫开发。 准备工作 所需工具 Python 3.6 requests库 Beautiful…

Linux上位机开发实践(MPP平台的核心构成)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 芯片行业是一个赢者通吃的行业。也就是说细分领域的前两名,相比较后来者而言,拥有很多无可比拟的优势。以安防市场的soc来说…

企业级风控系统设计:速卖通API数据+区块链存证防篡改方案

以下是一个基于速卖通 API 数据与区块链存证防篡改技术相结合的企业级风控系统设计方案: 一、系统目标 该风控系统旨在利用速卖通 API 实时获取海量交易数据,并借助区块链的不可篡改特性对关键数据进行存证,通过智能化分析识别潜在风险&…

python:将mp4视频快进播放,并保存新的视频

本文将介绍将mp4视频快进播放,并保存新的视频的python代码。 import subprocessdef speed_up_video(input_path, output_path, speed2.0):"""快进播放视频(加速播放):param input_path: 输入的视频文件路径:param output_pat…

paddle ocr

paddle ocr paddle ocr笔记准备工作referenceto onnx文本检测文本检测文字识别 paddle ocr笔记 准备工作 下载字典ppocr_keys_v1.txt,下标从1开始模型转换 reference paddlepaddle to onnx 下载模型,或者直接使用python跑一下并且把本地模型拿过来…

怎么简单设计一个文件上传系统?

关于文件上传系统有几个最主要的核心点需要解决: 如何支持超大文件上传 避免重复文件存储,节省空间 限流问题 大文件上传 假设有个 10 G 的文件需要上传,正常情况下是将文件转成流传到后端,如果不做任何处理,前端直传&#x…

k8s基础知识总结node+pod(上)

一、概念: k8s(Kubernetes )是一个开源的容器编排平台,用于容器化应用程序的部署、扩展和管理。使运维人员能够轻松地管理容器化应用的整个生命周期,包括容器的调度、资源分配、服务发现、负载均衡、自动伸缩以及故障…