7

TPLを利用するコードに次の設定があります。

  • 私のクラスの1つのフィールド:private CancellationTokenSource _cancellationTokenSource;
  • このCancellationTokeSourceは、その特定のcancellationtokenを使用するTPLタスクを作成するたびにインスタンス化されます

実際の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 => ...'ブロック)は実際に機能します。キャンセルのみは機能しません。誰かが理由を見たり知ったりしますか?

4

1 に答える 1

8

同じキャンセルトークンを使用しているため、キャンセルの継続はキャンセルされます。

あなたがそれについて考えるならば、それは完全に理にかなっています:あなたが「私はすべての処理をキャンセルしたい」と言うとき、あなたは実際にあなたが望むものを手に入れます。UIの更新を含め、すべての処理が停止します。

ContinueWhenAny解決策は、キャンセル、エラー、および継続にキャンセルトークンを使用しないことです。そうすれば、これらの継続は常に実行されます。

于 2012-05-12T11:18:47.400 に答える