1

次のシナリオが得られました。

class Program
{
    static void Main(string[] args)
    {
        // trigger the delayed function
        trigger();

        // cancel the running task.
        _token.Cancel();

        // keep window open ;-)
        Console.ReadLine();

    }

    private static CancellationTokenSource _token = null;
    private static async void trigger()
    {
        _token = new CancellationTokenSource();

        try
        {
            // run task
            await Task.Run(async () =>
            {
                // wait time
                await Task.Delay(2500);

                // we should be cancelled here !!
                Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
                Console.WriteLine("SHOULD NOT HAPPEN");

            }, _token.Token);
        }
        catch (TaskCanceledException)
        {
        }
    }
}

IMO の予想される動作は、Task.Delay(2500)が処理された後にタスクの操作がほとんどキャンセルされることです。

しかし、コンソールは印刷しています:

IsCancellationRequested=True
SHOULD NOT HAPPEN

これは単なるバグのように感じます。CancellationTokenをパラメーターとしてTask.Delay -Function に追加すると、期待どおりに機能します。

では、タスク内の関数がTask.Delayを使用している場合、キャンセルを処理する方法はわかりません。

4

2 に答える 2

3

.Net でのキャンセルは協調的です。パラメーターとしてトークンを渡すと、トークンTask.Runは返されたタスクにのみ関連付けられます。

タスクを実際にキャンセルするには、タスク自体の内部のトークンを確認する必要があります。遅延中にタスクをキャンセルしたい場合は、Task.Delayメソッドにトークンを渡す必要があります。それ以外の場合は、遅延の前後にのみ確認できます。

await Task.Run(async () =>
{
    _token.Token.ThrowIfCancelltionRequested();
    await Task.Delay(2500, _token.Token);
    _token.Token.ThrowIfCancelltionRequested();

    Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
    Console.WriteLine("SHOULD NOT HAPPEN");

}, _token.Token);
于 2015-07-10T15:21:01.920 に答える
1

MSDN のすばらしい記事は次のとおりです: https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx

呼び出しスレッドは強制的にタスクを終了しません。キャンセルが要求されたことを通知するだけです。タスクが既に実行されている場合、ユーザー デリゲートは要求に気づき、適切に応答する必要があります。タスクの実行前にキャンセルが要求された場合、ユーザー デリゲートは実行されず、タスク オブジェクトは Canceled 状態に遷移します。

i3arnon が提案したように、実際の作業を実行する前に、状態を確認して例外をスローできます。記事からのコードの抜粋:

...
  // Was cancellation already requested?  
      if (ct.IsCancellationRequested == true) {
         Console.WriteLine("Task {0} was cancelled before it got started.",
                           taskNum);
         ct.ThrowIfCancellationRequested();
      } 
...
于 2015-07-10T15:25:38.367 に答える