C# 如何使用 CancellationToken 属性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15067865/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:57:39  来源:igfitidea点击:

How to use the CancellationToken property?

c#multithreadingasynchronousconcurrencysynchronization

提问by Fulproof

Compared to the preceding code for class RulyCanceler, I wanted to run code using CancellationTokenSource.

与前面的RulyCanceler 类代码相比,我想使用 CancellationTokenSource.

How do I use it as mentioned in Cancellation Tokens, i.e. without throwing/catching an exception? Can I use the IsCancellationRequestedproperty?

我如何像Cancellation Tokens 中提到的那样使用它,即不抛出/捕获异常?我可以使用IsCancellationRequested物业吗?

I attempted to use it like this:

我试图像这样使用它:

cancelToken.ThrowIfCancellationRequested();

and

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

but this gave a run-time error on cancelToken.ThrowIfCancellationRequested();in method Work(CancellationToken cancelToken):

但这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:

The code that I successfully ran caught the OperationCanceledException in the new thread:

我成功运行的代码在新线程中捕获了 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();
      }
    }
  }
}

采纳答案by Sasha

You can implement your work method as follows:

您可以按如下方式实现您的工作方法:

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

That's it. You always need to handle cancellation by yourself - exit from method when it is appropriate time to exit (so that your work and data is in consistent state)

就是这样。你总是需要自己处理取消——在适当的时候退出方法退出(这样你的工作和数据处于一致的状态)

UPDATE:I prefer not writing while (!cancelToken.IsCancellationRequested)because often there are few exit points where you can stop executing safely across loop body, and loop usually have some logical condition to exit (iterate over all items in collection etc.). So I believe it's better not to mix that conditions as they have different intention.

更新:我不喜欢写,while (!cancelToken.IsCancellationRequested)因为通常很少有退出点可以在循环体中安全地停止执行,并且循环通常有一些逻辑条件可以退出(迭代集合中的所有项目等)。所以我认为最好不要混合这些条件,因为它们有不同的意图。

Cautionary note about avoiding CancellationToken.ThrowIfCancellationRequested():

关于避免的注意事项CancellationToken.ThrowIfCancellationRequested()

Comment in questionby Eamon Nerbonne:

Eamon Nerbonne 有问题评论

... replacing ThrowIfCancellationRequestedwith a bunch of checks for IsCancellationRequestedexits gracefully, as this answer says. But that's not just an implementation detail; that affects observable behavior: the task will no longer end in the cancelled state, but in RanToCompletion. And that can affect not just explicit state checks, but also, more subtly, task chaining with e.g. ContinueWith, depending on the TaskContinuationOptionsused. I'd say that avoiding ThrowIfCancellationRequestedis dangerous advice.

......正如this answer所说,优雅地替换ThrowIfCancellationRequested为一堆IsCancellationRequested退出检查。但这不仅仅是一个实现细节;这会影响可观察行为:任务将不再以取消状态结束,而是以RanToCompletion. 这不仅会影响显式状态检查,而且会更微妙地影响使用 eg 的任务链接ContinueWith,具体取决于所TaskContinuationOptions使用的。我会说避免ThrowIfCancellationRequested是危险的建议。

回答by user3285954

@BrainSlugs83

@BrainSlugs83

You shouldn't blindly trust everything posted on stackoverflow. The comment in Jens code is incorrect, the parameter doesn't control whether exceptions are thrown or not.

您不应该盲目相信在 stackoverflow 上发布的所有内容。Jens代码中的注释不正确,参数不控制是否抛出异常。

MSDN is very clear what that parameter controls, have you read it? http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx

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

If throwOnFirstExceptionis true, an exception will immediately propagate out of the call to Cancel, preventing the remaining callbacks and cancelable operations from being processed. If throwOnFirstExceptionis false, this overload will aggregate any exceptions thrown into an AggregateException, such that one callback throwing an exception will not prevent other registered callbacks from being executed.

如果throwOnFirstException为 true,则异常将立即从对 Cancel 的调用传播出去,从而阻止处理剩余的回调和可取消操作。如果 throwOnFirstException为 false,则此重载会将抛出的任何异常聚合到 中AggregateException,这样抛出异常的回调不会阻止其他已注册的回调被执行。

The variable name is also wrong because Cancel is called on CancellationTokenSourcenot the token itself and the source changes state of each token it manages.

变量名称也是错误的,因为 CancelCancellationTokenSource不是在令牌本身上调用的,并且源会更改它管理的每个令牌的状态。

回答by Titus

You canuse ThrowIfCancellationRequestedwithout handling the exception!

可以使用ThrowIfCancellationRequested不处理异常!

The use of ThrowIfCancellationRequestedis meant to be used from within a Task(not a Thread). When used within a Task, you do not have to handle the exception yourself (and get the Unhandled Exception error). It will result in leaving the Task, and the Task.IsCancelledproperty will be True. No exception handling needed.

的使用ThrowIfCancellationRequested意味着在 a Task(不是 a Thread)中使用。在 a 中使用时Task,您不必自己处理异常(并获得未处理的异常错误)。这将导致离开Task,并且该Task.IsCancelled属性将为 True。不需要异常处理。

In your specific case, change the Threadto a Task.

在您的特定情况下,将 更改Thread为 a Task

Task t = null;
try
{
    t = Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}

if (t.IsCancelled)
{
    Console.WriteLine("Canceled!");
}

回答by Jesse Jiang

You can create a Task with cancellation token, when you app goto background you can cancel this token.

您可以使用取消令牌创建任务,当您应用转到后台时,您可以取消此令牌。

You can do this in PCL https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle

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

Anther solution is user Timer in Xamarin.Forms, stop timer when app goto background https://xamarinhelp.com/xamarin-forms-timer/

花药解决方案是 Xamarin.Forms 中的用户计时器,当应用程序转到后台时停止计时器 https://xamarinhelp.com/xamarin-forms-timer/

回答by Mahbubur Rahman

You have to pass the CancellationTokento the Task, which will periodically monitors the token to see whether cancellation is requested.

您必须将 传递CancellationToken给 Task,它会定期监视令牌以查看是否请求取消。

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(); 

In this case, the operation will end when cancellation is requested and the Taskwill have a RanToCompletionstate. If you want to be acknowledged that your task has been cancelled, you have to use ThrowIfCancellationRequestedto throw an OperationCanceledExceptionexception.

在这种情况下,操作将在请求取消时结束,并且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(); 

Hope this helps to understand better.

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