Comparado ao código anterior para a classe RulyCanceler , eu queria executar o código usando CancellationTokenSource
.
Como faço para usá-lo conforme mencionado em Tokens de cancelamento , ou seja, sem lançar / capturar uma exceção? Posso usar a IsCancellationRequested
propriedade?
Tentei usá-lo assim:
cancelToken.ThrowIfCancellationRequested();
e
try
{
new Thread(() => Work(cancelSource.Token)).Start();
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled!");
}
mas isso gerou um erro de tempo de execução cancelToken.ThrowIfCancellationRequested();
no método 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:
O código que executei com sucesso capturou a OperationCanceledException no novo thread:
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();
}
}
}
}
CancellationTokenSource
com métodos assíncronos, métodos de longa execução com pesquisa e retorno de chamada.Respostas:
Você pode implementar seu método de trabalho da seguinte maneira:
É isso aí. Você sempre precisa lidar com o cancelamento sozinho - saia do método quando for o momento apropriado para sair (de modo que seu trabalho e dados estejam em um estado consistente)
ATUALIZAÇÃO: eu prefiro não escrever
while (!cancelToken.IsCancellationRequested)
porque geralmente existem poucos pontos de saída onde você pode parar a execução com segurança no corpo do loop, e o loop geralmente tem alguma condição lógica para sair (iterar sobre todos os itens da coleção, etc.). Então eu acredito que é melhor não misturar essas condições, pois elas têm intenções diferentes.Nota de advertência sobre como evitar
CancellationToken.ThrowIfCancellationRequested()
:Comentário em questão por Eamon Nerbonne :
fonte
@ BrainSlugs83
Você não deve confiar cegamente em tudo postado no stackoverflow. O comentário no código Jens está incorreto, o parâmetro não controla se as exceções são lançadas ou não.
O MSDN é muito claro sobre o que esse parâmetro controla, você leu? http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx
O nome da variável também está errado porque Cancel é chamado
CancellationTokenSource
não no token em si e a origem muda o estado de cada token que gerencia.fonte
Você pode criar uma Tarefa com token de cancelamento, ao aplicar o goto background, você pode cancelar esse token.
Você pode fazer isso em PCL https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle
Outra solução é o Timer do usuário em Xamarin.Forms, pare o cronômetro quando o aplicativo for para o fundo https://xamarinhelp.com/xamarin-forms-timer/
fonte
Você pode usar
ThrowIfCancellationRequested
sem lidar com a exceção!O uso de
ThrowIfCancellationRequested
destina-se a ser usado de dentro de aTask
(não aThread
). Quando usado em aTask
, você não precisa tratar a exceção sozinho (e obter o erro de exceção não tratada). Isso resultará no abandono doTask
e aTask.IsCancelled
propriedade será True. Nenhuma manipulação de exceção necessária.No seu caso específico, altere o
Thread
para aTask
.fonte
t.Start()
e nãoTask.Run()
?Você deve passar o
CancellationToken
para a Tarefa, que monitorará periodicamente o token para ver se o cancelamento é solicitado.Nesse caso, a operação será encerrada quando o cancelamento for solicitado e o
Task
terá umRanToCompletion
estado. Se você quiser ser informado de que sua tarefa foi cancelada , useThrowIfCancellationRequested
para lançar umaOperationCanceledException
exceção.Espero que isso ajude a entender melhor.
fonte