c# Task任務(wù)的取消方式
Task任務(wù)的取消
c# 任務(wù)的取消,需要用到CancellationTokenSource類,CancellationToken結(jié)構(gòu)體。
注意:CancellationTokenSource是class類型,而CancellationToken是struct結(jié)構(gòu)體。
任務(wù)內(nèi)部"監(jiān)聽"CancellationToken方法
任務(wù)的內(nèi)部在合適的時候不停地調(diào)用CancellationToken的ThrowIfCancellationRequested()方法,這個函數(shù)會拋出一個叫做OperationCanceledException的異常,它的實現(xiàn)(微軟開源代碼)如下:
public void ThrowIfCancellationRequested() { if (IsCancellationRequested) ThrowOperationCanceledException(); }
下面的列子通過Task.Run產(chǎn)生了一個任務(wù)。Task任務(wù)的內(nèi)部正式通過拋出OperationCanceledException異常達到被取消的目的。而任務(wù)的外部則是通過調(diào)用CancellationTokenSource實例的Cancel()方法來觸發(fā)取消的動作的。
下面的例子是一個取消Task任務(wù)的例子
using System; using System.Threading; using System.Threading.Tasks; class Program { static async Task Main() { var tokenSource2 = new CancellationTokenSource(); CancellationToken ct = tokenSource2.Token; var tokenSource3 = new CancellationTokenSource(); var task = Task.Run(() => { // Were we already canceled? ct.ThrowIfCancellationRequested(); bool moreToDo = true; while (moreToDo) { // Poll on this property if you have to do // other cleanup before throwing. // Clean up here, then... if(ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } } },tokenSource2.Token); // Pass same token to Task.Run. Thread.Sleep(5000); tokenSource2.Cancel(); // Just continue on this thread, or await with try-catch: try { await task; } catch (OperationCanceledException e) { Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}"); bool eqs = e.CancellationToken.Equals(tokenSource3.Token); System.Console.WriteLine($"Equals' result: {eqs}."); System.Console.WriteLine($"Task's status: {task.Status}"); } catch (Exception ex) { System.Console.WriteLine(ex.Message); } finally { tokenSource2.Dispose(); } Console.ReadKey(); } } /* The operation was canceled. OperationCanceledException thrown with message: The operation was canceled. Equals' result: False. Task's status: Canceled */
這個例子中我們在Task的外部創(chuàng)建了2個CancellationTokenSource實例,因為CancellationTokenSource類包含一個CancellationToken類的屬性Token,這也就意味著例子當中包含了兩個CancellationToken實例。
ThrowIfCancellationRequested()方法會把調(diào)用它的CancellationToken實例也作為參數(shù)一起攜帶拋出。
因此catch塊參數(shù)e中包含的是tokenSource2.Token,因此它與tokenSource3.Token進行相等比較輸出一定是false。
又因為Task.Run()方法中傳入的第二個參數(shù)也是tokenSource2.Token,Task核心框架內(nèi)部會比較OperationCanceledException異常中攜帶的CancellationToken實例和Task.Run()方法中傳入的CancellationToken實例,如果兩者是一樣的,則Task的status狀態(tài)設(shè)為Canceled,表示成功取消;如果兩者不一樣,Task任務(wù)仍然會退出,但是Task的status狀態(tài)設(shè)為Faulted,表示出錯。
如果將第29行改為:
},tokenSource3.Token); // Pass same token to Task.Run.
則,結(jié)果輸出如下:
OperationCanceledException thrown with message: The operation was canceled.
Equals' result: False.
Task's status: Faulted
看起來,Task任務(wù)也被取消了,但是實際上是由于出錯而退出。因此,Task.Run的第二個參數(shù)可以用來確保內(nèi)部實際引發(fā)取消異常的CancellationToken實例和Task.Run傳入的CancellationToken實例要一致才能成功取消,否則框架會誤認為你是誤操作而導(dǎo)致退出的。因此,Task.Run的CancellationToken參數(shù)是為了更加安全。
如果將29行改為不帶CancellationToken參數(shù)的重載函數(shù),那么返回的也是一樣的Faulted結(jié)果。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#連續(xù)任務(wù)Task.ContinueWith方法
這篇文章介紹了C#中的連續(xù)任務(wù)Task.ContinueWith方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04使用C# Winform應(yīng)用程序獲取網(wǎng)頁源文件的解決方法
本篇文章是對使用C# Winform應(yīng)用程序獲取網(wǎng)頁源文件的方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05C#使用Newtonsoft.Json庫實現(xiàn)JSON數(shù)據(jù)中某個字段值的提取功能
在C#中,可以使用Newtonsoft.Json庫(也稱為Json.NET)來處理JSON數(shù)據(jù),下面將通過幾個示例來展示如何從JSON格式的文本中提取某個字段的值,并將其存儲到字符串、列表或其他泛型集合中,需要的朋友可以參考下2025-03-03