如何使用的CancellationToken属性?(How to use the Cancellat

2019-07-20 11:47发布

相比于前面的代码类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();
      }
    }
  }
}

Answer 1:

您可以按以下步骤实现你的工作方法:

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

而已。 你总是需要自己处理取消 - 从方法退出时,它是适当的时候退出(让您的工作和数据是一致的状态)

更新:我不想写while (!cancelToken.IsCancellationRequested)因为经常有一些出口点在那里你可以停止整个循环体安全执行和循环通常有一定的逻辑条件退出(遍历集合中的所有等项目)。 所以,我认为这是最好不要混用,由于他们的条件有不同的打算。



Answer 2:

@ BrainSlugs83

你不应该盲目地相信一切都张贴在计算器。 在延代码的注释是不正确,参数不控制异常是否抛出与否。

MSDN是很清楚什么参数控制,你看过吗? http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx

如果throwOnFirstException是真实的,一个异常将立即传播,通话到取消,防止正在处理剩余的回调和取消操作。 如果throwOnFirstException是假的,这个重载将聚集扔进AggregateException任何异常,执行这样一个回调抛出一个异常,也不会阻止其他已注册的回调从。

变量名称也是错误的,因为取消被称为上CancellationTokenSource不令牌本身和源改变的每个令牌它所管理的状态。



Answer 3:

你可以使用ThrowIfCancellationRequested不处理例外!

使用ThrowIfCancellationRequested的是指从一个任务 (不是螺纹)内使用。 当一个任务中使用,你不必自己处理异常(并获得了未处理的异常错误)。 这将导致离开任务和Task.IsCancelled属性为真。 处理不需要的异常。

在特定情况下,主题更改为任务。

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


Answer 4:

您可以创建一个任务与取消标记,当你应用程式转到后台,你可以取消此令牌。

您可以在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/



Answer 5:

你必须在传递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(); 

希望这有助于更好地理解。



文章来源: How to use the CancellationToken property?