C#中如何中止已跟踪的Task任务?
解决方案
核心前提
.NET 中不存在安全强制中止Task的 API,所有任务取消都遵循协作式取消机制,必须配合CancellationToken(取消令牌)实现。你现有代码仅存储Task对象无法完成中止操作,需要按以下步骤调整:
步骤1:修改TrackedProgress类,关联取消令牌源
新增CancellationTokenSource字段存储对应任务的取消控制器:
public sealed class TrackedProgress { internal DateTime StartedAt { get; set; } public Task Job { get; set; } public int? Duration { get; set; } // 新增:关联任务的取消源 internal CancellationTokenSource Cts { get; set; } public TrackedProgress(Task job, CancellationTokenSource cts) { StartedAt = DateTime.Now; Job = job; Cts = cts; } public TrackedProgress(DateTime startedAt, Task job, CancellationTokenSource cts) { StartedAt = startedAt; Job = job; Cts = cts; } }
步骤2:调整ProgressTracker的TryStart方法
修改方法签名,要求传入可接收取消令牌的任务委托,内部自动创建取消令牌源绑定到任务:
public bool TryStart(string name, Func<CancellationToken, Task> taskFactory) { if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException(nameof(name)); } if (taskFactory == null) { throw new ArgumentNullException(nameof(taskFactory)); } // 为每个任务创建独立的取消源 var cts = new CancellationTokenSource(); var task = taskFactory(cts.Token); return _tracker.TryAdd(name, new TrackedProgress(task, cts)); }
如果要兼容原有传入Task的调用方式,你需要要求调用方自行将CancellationToken传入任务,同时在调用TryStart时额外传入对应的CancellationTokenSource参数即可。
步骤3:实现TryAbort取消逻辑
调用对应取消源的Cancel方法触发任务取消,完成后释放资源:
public bool TryAbort(string name, out int? duration) { duration = null; if (_tracker.TryRemove(name, out TrackedProgress progress)) { if(!progress.Job.IsCanceled && !progress.Job.IsCompleted) { // 触发取消信号 progress.Cts.Cancel(); // 可选:等待任务完成取消流程再释放 // progress.Job.Wait(1000); // 释放取消源资源 progress.Cts.Dispose(); } duration = (int)DateTime.Now.Subtract(progress.StartedAt).TotalSeconds; return true; } return false; }
步骤4:任务实现侧要求
你自己编写的任务逻辑必须主动监听取消令牌,否则取消信号不会生效,示例任务写法:
// 示例:支持取消的任务逻辑 async Task MyTaskLogic(CancellationToken token) { for(int i=0; i<100; i++) { // 监听取消信号,收到信号会抛出OperationCanceledException结束任务 token.ThrowIfCancellationRequested(); // 也可以主动判断后优雅退出 // if(token.IsCancellationRequested) return; await Task.Delay(1000, token); } } // 调用TryStart传入任务 tracker.TryStart("task1", MyTaskLogic);
注意:不要使用
Thread.Abort这类强制中止线程的API,这类方法会导致进程状态不稳定、资源泄漏,.NET Core+版本中已经不支持该方法。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

