前言
在群里看到有人問如何取消這個 Task 的執行:
實際上這并不會取消S1eepMode1
方法的執行:
這是為什么呢?
原因
首先,讓我們看看s_cts.Cancel()
都做了啥:
public?void?Cancel()?=>?Cancel(false);public?void?Cancel(bool?throwOnFirstException)
{ThrowIfDisposed();NotifyCancellation(throwOnFirstException);
}private?void?NotifyCancellation(bool?throwOnFirstException)
{//?If?we're?the?first?to?signal?cancellation,?do?the?main?extra?work.if?(!IsCancellationRequested?
&&?Interlocked.CompareExchange(ref?_state,?NotifyingState,?NotCanceledState)?==?NotCanceledState){...}
}
實際上,Cancel
方法僅僅是將變量_state
的值改為NotifyingState
。
那Task.Run
傳遞s_cts.Token
又有什么用呢?
public?static?Task<TResult>?Run<TResult>(Func<Task<TResult>?>?function,?CancellationToken?cancellationToken)
{if?(function?==?null)?ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);//?Short-circuit?if?we?are?given?a?pre-canceled?tokenif?(cancellationToken.IsCancellationRequested)return?Task.FromCanceled<TResult>(cancellationToken);...
}
原來,是在創建 Task 前先檢查令牌是否已經Cancel
,以便快速終止。
那么,到底怎么才能Cacel
已創建的Task
呢?
實現
其實,Task.Run
的方法實現已經告訴我們正確的解決方案,那就是判斷cancellationToken.IsCancellationRequested
:
public?static?async?Task?S1eepMode1(CancellationToken?cancellationToken)
{while?(true){if?(cancellationToken.IsCancellationRequested)return;...}
}
另外,也可以采取拋出異常的方式:
public?static?async?Task?S1eepMode1(CancellationToken?cancellationToken)
{while?(true){cancellationToken.ThrowIfCancellationRequested();...}
}
示例應用程序并不會捕獲到這個異常,相關問題可以看我以前的文章《如何保證執行異步方法時不會遺漏 await 關鍵字》
結論
在創建 Task 時請記住,即使你執行了令牌取消操作,也并不意味著 Task 會停止運行。
添加微信號【MyIO666】,邀你加入技術交流群