我的代码中有以下使用 TPL 的设置:
- 我的类中的一个字段:private CancellationTokenSource _cancellationTokenSource;
- 每次我创建使用特定取消 token 的 TPL 任务时,都会启动此 CancellationTokeSource
实际的 TPL 任务如下所示:
var dataRetrievalTask = new Task<List<myType>>(() =>
{
// retrieve data and do something
foreach (var a in retrievalMethod())
{
if (_cancellationTokenSource.Token.IsCancellationRequested)
_cancellationTokenSource.Token.ThrowIfCancellationRequested();
// do something if not cancelled
}
}
return filledListOfMyType;
}, _cancellationTokenSource.Token);
// define what shall happen if data retrievel finished without any problems
var writingLoadedDataToGridTask = dataRetrievalTask.ContinueWith(task =>
{
// do something in case we ran to completion without error
}, _cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, currentScheduler);
// what to do in case cancellation was performed
var loadingDataCancelledTask = dataRetrievalTask.ContinueWith(task =>
{
someLabel.Text = "Data retrieval canceled.";
},_cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnCanceled, currentScheduler);
// what to do in case an exception / error occured
var loadingDataFaulted = dataRetrievalTask.ContinueWith(task =>
{
someLabel.Text = string.Format("Data retrieval ended with an Error.");
}, _cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnFaulted, currentScheduler);
// when any of the continuation tasks ran through, reset ui controls / buttons etc
Task.Factory.ContinueWhenAny(new[] { writingLoadedDataToGridTask, loadingDataCancelledTask, loadingDataFaulted }, task =>
{
// reset controls and all that
}, _cancellationTokenSource.Token, TaskContinuationOptions.None, currentScheduler);
dataRetrievalTask.Start();
现在我的问题是,当在某个地方(在取消按钮的 .Click 事件处理程序中)调用 _cancellationTokenSource.Cancel() 方法时,不会调用特定的 loadingDataCancelledTask 的主体/方法。
我在这里做错了什么?我正在使用并移交相同的 _cancellationTokenSource.Token 实例...以及其他所有内容(“writingLoadedDataToGridTask”和“loadingDataFaulted”任务以及以下“Task.Factory.ContinueWhenAny(new [] {writingLoadedDataToGridTask,loadingDataCancelledTask,loadingDataFaulted },任务) => ...' block )确实有效。只有取消不起作用。有人看到/知道为什么吗?
最佳答案
您的取消延续正在被取消,因为它使用相同的取消 token 。
如果你仔细想想,这是完全有道理的:当你说“我想取消所有处理”时,你实际上得到了你所要求的。所有处理都会停止,包括更新 UI。
解决方案是不要将取消 token 用于取消、错误和 ContinueWhenAny
延续。这样这些延续就会始终运行。
关于.net - TPL 取消延续从未调用已取消的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10563214/