Como: Escutar solicitações de cancelamento por pesquisa
O exemplo a seguir mostra uma maneira que o código do usuário pode pesquisar um símbolo de cancelamento em intervalos regulares para ver se cancelamento foi solicitado o thread de chamada. Este exemplo usa a System.Threading.Tasks.Task tipo, mas o mesmo padrão que se aplica a operações assíncronas criadas diretamente pela System.Threading.ThreadPool tipo ou o System.Threading.Thread tipo.
Exemplo
Pesquisa requer algum tipo de código de loop ou recursiva periodicamente pode ler o valor do Boolean IsCancellationRequested propriedade. Se você estiver usando o System.Threading.Tasks.Task , tipo e estão aguardando a tarefa ser concluída no thread de chamada, você pode usar o ThrowIfCancellationRequested método para verificar a propriedade e lançar a exceção. Usando esse método, você garantir que a exceção correta é acionada em resposta a uma solicitação. Se você estiver usando um Task, e em seguida, chamar este método é melhor do que lançar manualmente uma OperationCanceledException. Se você não precisa lançar a exceção, basta verificar a propriedade e retorno do método se a propriedade for true.
Class CancelByPolling
Shared Sub Main()
Dim tokenSource As New CancellationTokenSource()
' Toy object for demo purposes
Dim rect As New Rectangle()
rect.columns = 1000
rect.rows = 500
' Simple cancellation scenario #1. Calling thread does not wait
' on the task to complete, and the user delegate simply returns
' on cancellation request without throwing.
Task.Factory.StartNew(Sub() NestedLoops(rect, tokenSource.Token), tokenSource.Token)
' Simple cancellation scenario #2. Calling thread does not wait
' on the task to complete, and the user delegate throws
' OperationCanceledException to shut down task and transition its state.
' Task.Factory.StartNew(Sub() PollByTimeSpan(tokenSource.Token), tokenSource.Token)
Console.WriteLine("Press 'c' to cancel")
If Console.ReadKey().KeyChar = "c"c Then
tokenSource.Cancel()
Console.WriteLine("Press any key to exit.")
End If
Console.ReadKey()
End Sub
Shared Sub NestedLoops(ByVal rect As Rectangle, ByVal token As CancellationToken)
For x As Integer = 0 To rect.columns
For y As Integer = 0 To rect.rows
' Simulating work.
Thread.SpinWait(5000)
Console.Write("0' end block,1' end block ", x, y)
Next
' Assume that we know that the inner loop is very fast.
' Therefore, checking once per row is sufficient.
If token.IsCancellationRequested = True Then
' Cleanup or undo here if necessary...
Console.WriteLine("\r\nCancelling after row 0' end block.", x)
Console.WriteLine("Press any key to exit.")
' then...
Exit For
' ...or, if using Task:
' token.ThrowIfCancellationRequested()
End If
Next
End Sub
End Class
class CancelByPolling
{
static void Main()
{
var tokenSource = new CancellationTokenSource();
// Toy object for demo purposes
Rectangle rect = new Rectangle() { columns = 1000, rows = 500 };
// Simple cancellation scenario #1. Calling thread does not wait
// on the task to complete, and the user delegate simply returns
// on cancellation request without throwing.
Task.Factory.StartNew(() => NestedLoops(rect, tokenSource.Token), tokenSource.Token);
// Simple cancellation scenario #2. Calling thread does not wait
// on the task to complete, and the user delegate throws
// OperationCanceledException to shut down task and transition its state.
// Task.Factory.StartNew(() => PollByTimeSpan(tokenSource.Token), tokenSource.Token);
Console.WriteLine("Press 'c' to cancel");
if (Console.ReadKey().KeyChar == 'c')
{
tokenSource.Cancel();
Console.WriteLine("Press any key to exit.");
}
Console.ReadKey();
}
static void NestedLoops(Rectangle rect, CancellationToken token)
{
for (int x = 0; x < rect.columns && !token.IsCancellationRequested; x++)
{
for (int y = 0; y < rect.rows; y++)
{
// Simulating work.
Thread.SpinWait(5000);
Console.Write("{0},{1} ", x, y);
}
// Assume that we know that the inner loop is very fast.
// Therefore, checking once per row is sufficient.
if (token.IsCancellationRequested)
{
// Cleanup or undo here if necessary...
Console.WriteLine("\r\nCancelling after row {0}.", x);
Console.WriteLine("Press any key to exit.");
// then...
break;
// ...or, if using Task:
// token.ThrowIfCancellationRequested();
}
}
}
}
Chamando ThrowIfCancellationRequested é extremamente rápida e não apresenta uma sobrecarga significativa em loops.
Se você estiver chamando ThrowIfCancellationRequested, você só precisa verificar explicitamente o IsCancellationRequested propriedade se você tiver outro trabalho a fazer em resposta para o cancelamento, além de lançar a exceção. Neste exemplo, você pode ver que o código realmente acessa a propriedade duas vezes: uma vez no acesso explícito e novamente na ThrowIfCancellationRequested método. Mas porque o ato de leitura de IsCancellationRequested propriedade envolve volátil de apenas uma instrução por acesso de leitura, o acesso a duplo é não significativo de uma perspectiva de desempenho. É preferível ainda para chamar o método, em vez de lançar manualmente a OperationCanceledException.