如何实现新调用DoSomething时自动取消上一次任务执行?
实现多次调用时自动取消上一次后台任务的方案
你的需求是典型的「取消前序任务,只保留最新任务执行」的场景,原代码的问题在于复用了同一个CancellationTokenSource实例,导致所有任务共享同一个取消令牌,无法精准控制上一次任务的取消。下面是修正后的实现方案:
// 存储当前的取消令牌源 private CancellationTokenSource _cancellationTokenSource; // 锁对象,保证多线程调用时的线程安全 private readonly object _lockObj = new object(); void DoSomething() { lock (_lockObj) { // 1. 取消上一次的任务(如果存在未完成的任务) _cancellationTokenSource?.Cancel(); // 2. 释放旧令牌源的资源(避免内存泄漏) _cancellationTokenSource?.Dispose(); // 3. 创建新的令牌源,供当前任务使用 _cancellationTokenSource = new CancellationTokenSource(); } // 启动新的后台任务 Task.Run(async () => { try { // 将当前令牌传入长任务,让任务能响应取消信号 await LongRunningTask(_cancellationTokenSource.Token); } catch (OperationCanceledException) { // 任务被取消时的自定义逻辑,比如打日志 Console.WriteLine("前序任务被取消"); } }).ContinueWith(t => { // 处理任务最终状态 if (t.IsFaulted && !t.IsCanceled) { Console.WriteLine($"任务执行出错:{t.Exception?.InnerException?.Message}"); } else if (t.IsCompletedSuccessfully) { Console.WriteLine("任务执行完成"); } }); } // 模拟耗时的长任务示例 async Task LongRunningTask(CancellationToken token) { // 长任务中需要主动检查取消信号,或者传入支持取消的异步方法 for (int i = 0; i < 10; i++) { // 检查是否收到取消指令,若有则抛出异常终止任务 token.ThrowIfCancellationRequested(); await Task.Delay(500, token); } }
关键细节说明
- 线程安全保障:用
lock包裹令牌源的替换逻辑,避免多线程并发调用时出现竞态问题(比如旧令牌还没取消就被替换)。 - 独立令牌管理:每次调用都创建新的
CancellationTokenSource,确保每一个任务都拥有专属的取消信号,不会互相干扰。 - 主动响应取消:长任务内部必须通过
token.ThrowIfCancellationRequested()或传入支持取消的异步方法(如Task.Delay),才能在收到取消信号时及时终止。 - 状态区分处理:通过
ContinueWith区分任务的「正常完成」「异常失败」「被取消」三种状态,避免错误处理混乱。
示例场景运行流程
DoSomething(); // 启动第一个任务,随后被第二个调用取消 DoSomething(); // 启动第二个任务,随后被第三个调用取消 DoSomething(); // 启动第三个任务,无后续调用,最终执行完成
对应输出大致为:
前序任务被取消 前序任务被取消 任务执行完成
内容的提问来源于stack exchange,提问作者zimmybln
相关产品推荐
相关产品推荐

