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();

现在我的问题是,当某处(在取消按钮的 .Click 事件处理程序中)调用 _cancellationTokenSource.Cancel() 方法时,不会调用特定的 loadingDataCancelledTask 的主体/方法。

我在这里做错了什么?我正在使用并移交相同的 _cancellationTokenSource.Token 实例...以及其他所有内容(“writingLoadedDataToGridTask”和“loadingDataFaulted”任务以及以下“Task.Factory.ContinueWhenAny(new[] { writingLoadedDataToGridTask, loadingDataCancelledTask, loadingDataFaulted }, task => ...'块)确实有效。只有取消没有。有人看到/知道为什么吗?

4

1 回答 1

8

您的取消继续被取消,因为它使用相同的取消令牌。

如果您考虑一下,这完全有道理:当您说“我想取消所有处理”时,您实际上得到了您所要求的。所有处理都会停止,包括更新 UI。

解决方案是不将取消令牌用于取消、错误和ContinueWhenAny继续。这样,这些延续总是运行。

于 2012-05-12T11:18:47.400 回答