web-dev-qa-db-ja.com

CancellationTokenプロパティの使用方法は?

前のコード RulyCancelerクラスの場合 と比較して、CancellationTokenSourceを使用してコードを実行したかったのです。

キャンセルトークン で説明したように、つまり例外をスロー/キャッチせずに使用するにはどうすればよいですか? IsCancellationRequestedプロパティを使用できますか?

私はこれを次のように使用しようとしました:

cancelToken.ThrowIfCancellationRequested();

そして

try
{
  new Thread(() => Work(cancelSource.Token)).Start();
}
catch (OperationCanceledException)
{
  Console.WriteLine("Canceled!");
}

しかし、これにより、メソッドcancelToken.ThrowIfCancellationRequested();Work(CancellationToken cancelToken)で実行時エラーが発生しました。

System.OperationCanceledException was unhandled
  Message=The operation was canceled.
  Source=mscorlib
  StackTrace:
       at System.Threading.CancellationToken.ThrowIfCancellationRequested()
       at _7CancellationTokens.Token.Work(CancellationToken cancelToken) in C:\xxx\Token.cs:line 33
       at _7CancellationTokens.Token.<>c__DisplayClass1.<Main>b__0() in C:\xxx\Token.cs:line 22
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

私が正常に実行したコードは、新しいスレッドでOperationCanceledExceptionをキャッチしました。

using System;
using System.Threading;
namespace _7CancellationTokens
{
  internal class Token
  {
    private static void Main()
    {
      var cancelSource = new CancellationTokenSource();
      new Thread(() =>
      {
         try
         {
           Work(cancelSource.Token); //).Start();
         }
         catch (OperationCanceledException)
         {
            Console.WriteLine("Canceled!");
         }
         }).Start();

      Thread.Sleep(1000);
      cancelSource.Cancel(); // Safely cancel worker.
      Console.ReadLine();
    }
    private static void Work(CancellationToken cancelToken)
    {
      while (true)
      {
        Console.Write("345");
        cancelToken.ThrowIfCancellationRequested();
      }
    }
  }
}
99
Fulproof

次のように作業メソッドを実装できます。

private static void Work(CancellationToken cancelToken)
{
    while (true)
    {
        if(cancelToken.IsCancellationRequested)
        {
            return;
        }
        Console.Write("345");
    }
}

それでおしまい。常に自分でキャンセルを処理する必要があります-終了する適切な時間になったらメソッドを終了します(作業とデータが一貫した状態になるように)

PDATE:ループボディ全体で安全に実行を停止できる終了ポイントが少ないことが多いため、while (!cancelToken.IsCancellationRequested)を記述しないことをお勧めします。 。ですから、意図が異なるため、その条件を混ぜない方が良いと思います。

125
Sasha

しゅう

Stackoverflowに投稿されたすべてを盲目的に信頼するべきではありません。 Jensコードのコメントは正しくありません。パラメーターは、例外がスローされるかどうかを制御しません。

MSDNはそのパラメーターが何を制御するかを非常に明確にしています。読んでいますか? http://msdn.Microsoft.com/en-us/library/dd321703(v = vs.110).aspx

ThrowOnFirstExceptionがtrueの場合、例外はすぐにCancelの呼び出しから伝達され、残りのコールバックとキャンセル可能な操作が処理されないようにします。 throwOnFirstExceptionがfalseの場合、このオーバーロードはAggregateExceptionにスローされたすべての例外を集約し、例外をスローする1つのコールバックが他の登録済みコールバックの実行を妨げないようにします。

トークン自体ではなくCancellationTokenSourceでCancelが呼び出され、ソースが管理する各トークンの状態を変更するため、変数名も間違っています。

24
user3285954

can例外を処理せずにThrowIfCancellationRequestedを使用します!

ThrowIfCancellationRequestedの使用は、タスク(スレッドではない)内から使用することを意図しています。タスク内で使用する場合、例外を自分で処理する必要はありません(未処理の例外エラーが発生します)。タスクが終了し、Task.IsCancelledプロパティがTrueになります。例外処理は必要ありません。

特定のケースでは、スレッドをタスクに変更します。

try
{
  Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}
if (t.IsCancelled)
  Console.WriteLine("Canceled!");
}
10
Titus

キャンセルトークンを使用してタスクを作成できます。バックグラウンドでアプリを実行すると、このトークンをキャンセルできます。

これはPCLで行うことができます https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle

var cancelToken = new CancellationTokenSource();
Task.Factory.StartNew(async () => {
    await Task.Delay(10000);
    // call web API
}, cancelToken.Token);

//this stops the Task:
cancelToken.Cancel(false);

別のソリューションは、Xamarin.Formsのユーザータイマーです。アプリがバックグラウンドに移動したらタイマーを停止します https://xamarinhelp.com/xamarin-forms-timer/

8
Jesse Jiang

CancellationTokenをタスクに渡す必要があります。タスクは定期的にトークンを監視して、キャンセルが要求されているかどうかを確認します。

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;  
Task task = Task.Run(() => {     
  while(!token.IsCancellationRequested) {
      Console.Write("*");         
      Thread.Sleep(1000);
  }
}, token);
Console.WriteLine("Press enter to stop the task"); 
Console.ReadLine(); 
cancellationTokenSource.Cancel(); 

この場合、キャンセルが要求されると操作が終了し、Taskの状態はRanToCompletionになります。 タスクがキャンセルされたであることを確認したい場合は、ThrowIfCancellationRequestedを使用してOperationCanceledException例外をスローする必要があります。

Task task = Task.Run(() =>             
{                 
    while (!token.IsCancellationRequested) {
         Console.Write("*");                      
        Thread.Sleep(1000);                 
    }           
    token.ThrowIfCancellationRequested();               
}, token)
.ContinueWith(t =>
 {
      t.Exception?.Handle(e => true);
      Console.WriteLine("You have canceled the task");
 },TaskContinuationOptions.OnlyOnCanceled);  

Console.WriteLine("Press enter to stop the task");                 
Console.ReadLine();                 
cancellationTokenSource.Cancel();                 
task.Wait(); 

これが理解を深めるのに役立つことを願っています。

2
Mahbubur Rahman