C# 
- Cancelamento de operações assíncronas - I
    
    
    ![]()  | 
    Hoje veremos como cancelar operações assíncronas na linguagem C#. | 
A plataforma .NET usa um modelo unificado para cancelamento cooperativo de operações assíncronas ou síncronas de longa duração. Este modelo é baseado em um objeto leve chamado token de cancelamento.
O objeto que invoca uma ou mais operações canceláveis, por exemplo, criando novas threads ou tarefas e passa o token para cada operação. As operações individuais podem, por sua vez, passar cópias do token para outras operações.
Mais tarde, o objeto que criou o token pode usá-lo para solicitar que as operações parem o que estão fazendo. Apenas o objeto solicitante pode emitir a solicitação de cancelamento, e cada ouvinte é responsável por perceber a solicitação e respondê-la de maneira adequada e oportuna.
O padrão geral para implementar o modelo de cancelamento cooperativo é o seguinte:
O framework de cancelamento é implementado como um conjunto de tipos relacionados, que estão listados na tabela a seguir.
| Nome do tipo | DESCRIÇÃO | 
|---|---|
| CancellationTokenSource | O objeto que cria um token de cancelamento, e também emite o pedido de cancelamento para todas as cópias desse token. | 
| CancellationToken | O tipo de valor leve passado a um ou mais ouvintes, normalmente como um parâmetro de método. Os ouvintes monitoram o valor da propriedade IsCancellationRequested do token por sondagem, retorno de chamada ou identificador de espera. | 
| OperationCanceledException | As sobrecargas do construtor desta exceção aceitam CancellationToken como um parâmetro. Os ouvintes podem, opcionalmente, lançar essa exceção para verificar a origem do cancelamento e notificar aos outros que ela respondeu a uma solicitação de cancelamento. | 
Vejamos a seguir como podemos realizar o cancelamento na prática.
Recursos usados:
Cancelando uma tarefa assíncrona
Vamos iniciar criando um tarefa de longa duração definindo o método OperacaoLongaDuracao() que retorna um Task<int>:
		private static Task<int> OperacaoLongaDuracao(int valor)
{
            return Task.Run(() =>
            {
                int resultado = 0;
                for (int i = 0; i < valor; i++)
                {
                    Thread.Sleep(50);
                    resultado += i;
                }
                return resultado;
            });
}
         | 
    
Aqui estou usando Thread.Sleep() que suspende a thread atual por um determinado tempo especificado em milissegundos para simular a longa duração.
A chamada deste método pode ser feita da seguinte forma:
		static async Task Main(string[] args)
{
        await ExecutaTaskAsync();
        Console.ReadKey();
}
public static async Task ExecutaTaskAsync()
{
            var stopwatch = new Stopwatch();
            stopwatch.Start();
		            Console.WriteLine("Resultado {0}", await OperacaoLongaDuracao(100));
            Console.WriteLine("Tempo gasto..." + stopwatch.Elapsed + "\n");   
 }
		 | 
	
Ocorre que aqui não estamos permitindo o cancelamento da tarefa. Vamos implementar o cancelamento usando o padrão geral e o token de cancelamento.
A primeira coisa a fazer é tornar o nosso método de longa duração cancelável passando o CancellationToken para o método como uma parâmetro que aqui eu defini como opcional.
		private static Task<int> OperacaoLongaDuracaoCancelavel(int valor, CancellationToken cancellationToken = default)
{
            Task<int> task = null;
		            task = Task.Run(() =>
            {
                int resultado = 0;
                for (int i = 0; i < valor; i++)
                {
                    // Verifica se foi solicitado o cancelamento
                    // se foi lança um TaskCanceledException.
                    if (cancellationToken.IsCancellationRequested)
                           throw new TaskCanceledException(task);
		                    Thread.Sleep(10);
                    resultado += i;
                }
                return resultado;
            });
            return task;
}
		 | 
	
Neste código estamos passando o CancellationToken para o método definindo o valor como default de forma a torná-lo não obrigatório.
A seguir estamos verificando se o método deve ser cancelado lendo a propriedade IsCancellationRequested.(Também é possível usar o método ThrowIfCancellationRequested, que lançará uma OperationCanceledException).
A seguir estamos lançando um exceção do tipo TaskCanceledException(), que que representa uma exceção usada para comunicar o cancelamento da tarefa, .e passando a tarefa.
A seguir podemos chamar o método passando o token de cancelamento com o valor Cancel e estamos usando um bloco try/cacth para tratar a exceção TaskCanceledException:
		class Program { private static CancellationTokenSource cancellationTokenSource; static async Task Main(string[] args) { try { await ExecutaTaskCancelamentoAsync(); } catch (TaskCanceledException ex) { Console.WriteLine(ex.Message); } Console.ReadKey(); }         public static async Task ExecutaTaskCancelamentoAsync()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
		            cancellationTokenSource = new CancellationTokenSource();
            cancellationTokenSource?.Cancel();
		Console.WriteLine($"Executou : {nameof(ExecutaTaskAsync)}"); Console.WriteLine("Resultado {0}", await OperacaoLongaDuracaoCancelavel(100, cancellationTokenSource.Token)); Console.WriteLine("Tempo gasto..." + stopwatch.Elapsed + "\n"); } ... }
		 | 
	
No método Main estamos usando um bloco try/catch para tratar a exceção que será lançada quando a tarefa for cancelada e chamando o método ExecutaTaskCancelamentoAsync.
Neste método estou criando uma instância de CancellationTokenSource e passando o token com a notificação de cancelamento. Isso vai cancelar a operação de imediato.
A seguir temos o resultado obtido:

Na próxima parte do artigo veremos como cancelar uma operação assíncrona em um período de tempo específico.
E estamos 
conversados... 
![]()
Não se turbe o 
vosso coração; credes em Deus, crede também em mim.
Na casa de meu Pai há muitas moradas. Se assim não fora, eu vo-lo teria dito. 
Pois vou preparar-vos lugar.
João 14:1,2
Referências: