已取消的任务上未调用TPL取消续订。

7

我在代码中使用TPL有以下设置:

  • 我的类中有一个字段:private CancellationTokenSource _cancellationTokenSource;
  • 每次创建使用特定取消令牌的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();

现在我的问题是,当 _cancellationTokenSource.Cancel() 方法在某个地方被调用时(在“取消”按钮的 .Click 事件处理程序中),该特定 loadingDataCancelledTask 的主体/方法不会被调用。
我在这里做错了什么?我正在使用并交出相同的 _cancellationTokenSource.Token 实例...和其他所有事情('writingLoadedDataToGridTask' 和 'loadingDataFaulted' 任务以及以下的 'Task.Factory.ContinueWhenAny(new[] { writingLoadedDataToGridTask, loadingDataCancelledTask, loadingDataFaulted }, task =>...' 块)实际上都起作用。只有取消操作没有起作用。有人看到/知道为什么吗?
1个回答

8

您的取消操作被取消了,因为它使用了相同的取消标记。

如果您思考一下就会明白:当您说“我想要取消所有处理”时,您实际上得到了您所要求的。所有的处理都停止了,包括更新UI界面的操作。

解决方案是不要在取消、错误和ContinueWhenAny延续中使用取消标记。这样这些延续总是运行。


1
哦,你这么说,现在我完全明白了,是的。非常感谢!! - Jörg Battermann
那么 'TaskContinuationOptions.OnlyOnCanceled' 是什么意思?它永远不会运行吗? - Alex F
这意味着当“基本任务”被取消时它会运行。但是您也可以选择取消继续执行。如果您不想这样做,请不要将取消令牌传递给它。 - usr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接