141

クラス RulyCancelerの前のコードと比較して、私は CancellationTokenSource.

Cancellation Tokensに記載されているように、つまり、例外をスロー/キャッチせずに使用するにはどうすればよいですか? 物件を利用でき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();
      }
    }
  }
}
4

4 に答える 4

172

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

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

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

更新:while (!cancelToken.IsCancellationRequested)ループ本体全体で安全に実行を停止できる終了ポイントがほとんどなく、ループには通常、終了する論理条件があるため (コレクション内のすべての項目を反復処理するなど)、記述しないことを好みます。意図が違うので混ぜないほうがいいと思います。

回避に関する注意事項CancellationToken.ThrowIfCancellationRequested()

イーモン・ネルボンヌによる問題のコメント:

...この回答が示すように、終了ThrowIfCancellationRequestedの一連のチェックを適切に置き換えます。IsCancellationRequestedしかし、これは単なる実装の詳細ではありません。観察可能な動作に影響を与える: タスクはキャンセルされた状態ではなく、RanToCompletion. そして、それは明示的な状態チェックだけでなく、より微妙ContinueWithに、TaskContinuationOptions使用される . ThrowIfCancellationRequested避けるのは危険なアドバイスだと思います。

于 2013-02-25T13:20:50.550 に答える
14

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

// CancellationTokenSource provides the token and have authority to cancel the token
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;  

// Task need to be cancelled with CancellationToken 
Task task = Task.Run(async () => {     
  while(!token.IsCancellationRequested) {
      Console.Write("*");         
      await Task.Delay(1000);
  }
}, token);

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

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

Task task = Task.Run(async () =>             
{                 
    while (!token.IsCancellationRequested) {
         Console.Write("*");                      
         await Task.Delay(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(); 

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

于 2019-02-20T07:05:14.070 に答える