与前面的代码for class 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();
}
}
}
}
答案 0 :(得分:124)
您可以按如下方式实施工作方法:
private static void Work(CancellationToken cancelToken)
{
while (true)
{
if(cancelToken.IsCancellationRequested)
{
return;
}
Console.Write("345");
}
}
就是这样。您总是需要自己处理取消 - 退出时退出方法(以便您的工作和数据处于一致状态)
更新:我不想写while (!cancelToken.IsCancellationRequested)
,因为通常很少有退出点可以在循环体上安全地停止执行,并且循环通常有一些逻辑条件退出(迭代收藏中的所有物品等)。所以我认为最好不要将这些条件混合起来,因为它们有不同的意图。
答案 1 :(得分:24)
@ BrainSlugs83
你不应该盲目信任stackoverflow上发布的所有内容。 Jens代码中的注释不正确,该参数不控制是否抛出异常。
MSDN非常清楚该参数控制的是什么,你读过它吗? http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx如果throwOnFirstException为true,则会立即发生异常 传播出来取消,阻止剩余 处理中的回调和可取消操作。如果 throwOnFirstException为false,此重载将聚合任何 抛出到AggregateException中的异常,例如一个回调 抛出异常不会阻止其他注册的回调 被执行。
变量名也是错误的,因为在CancellationTokenSource上调用了Cancel而不是令牌本身,并且源更改了它管理的每个令牌的状态。
答案 2 :(得分:10)
您可以在不处理异常的情况下使用ThrowIfCancellationRequested!
ThrowIfCancellationRequested的使用意味着在任务(非线程)中使用。 在Task中使用时,您不必自己处理异常(并获取Unhandled Exception错误)。它将导致离开Task,并且Task.IsCancelled属性将为True。无需处理异常。
在您的特定情况下,将线程更改为任务。
try
{
Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}
if (t.IsCancelled)
Console.WriteLine("Canceled!");
}
答案 3 :(得分:6)
您可以使用取消令牌创建任务,当您转到后台时,您可以取消此令牌。
您可以在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解决方案是Xamarin.Forms中的用户计时器,当应用程序转到后台时停止计时器 https://xamarinhelp.com/xamarin-forms-timer/
答案 4 :(得分:2)
您必须将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();
希望这有助于更好地理解。