TPL取消延续从未调用取消任务

时间:2012-05-12 11:15:01

标签: .net multithreading task-parallel-library task

我在使用TPL的代码中进行了以下设置:

  • 我班上的一个字段:private CancellationTokenSource _cancellationTokenSource;
  • 每次创建使用该特定canceltoken的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();

现在我的问题是,在某处(在Cancel-button的.Click事件处理程序中)调用_cancellationTokenSource.Cancel()方法时,不会调用特定的loadingDataCancelledTask的body /方法。

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

1 个答案:

答案 0 :(得分:8)

取消续订正在取消,因为它使用相同的取消令牌。

如果你仔细想想它是完全有道理的:当你说“我想取消所有处理”时,你实际上得到了你所要求的。所有处理都会停止,包括更新UI。

解决方案是不使用取消令牌来取消,错误和ContinueWhenAny延续。这样,这些延续总是在运行。