【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.pswp.cn/bicheng/75330.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75330.shtml
英文地址,請注明出處:http://en.pswp.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;也可能因為某臺…