前言
在群里看到有人问如何取消这个 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】,邀你加入技术交流群