Gör så här: Avbryt en aktivitet och dess underordnade
Det här exemplet visar hur du utför följande uppgifter:
- Skapa och starta en avbruten uppgift.
- Skicka en annulleringstoken till ditt användardelegat och eventuellt till aktivitetsinstansen.
- Lägg märke till och svara på begäran om annullering i användardelegaten.
- Du kan också observera i den anropande tråden att uppgiften avbröts.
Den anropande tråden avslutar inte uppgiften med tvång. det signalerar endast att annullering begärs. Om aktiviteten redan körs är det upp till användardelegaten att lägga märke till begäran och svara på rätt sätt. Om annullering begärs innan aktiviteten körs körs aldrig användardelegaten och aktivitetsobjektet övergår till tillståndet Avbrytd.
Exempel
Det här exemplet visar hur du avslutar en Task och dess underordnade som svar på en begäran om annullering. Det visar också att när ett användardelegat avslutas genom att utlösa en TaskCanceledExceptionkan den anropande tråden Wait också använda metoden eller WaitAll metoden för att vänta tills aktiviteterna har slutförts. I det här fallet måste du använda ett try/catch
block för att hantera undantagen i den anropande tråden.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static async Task Main()
{
// Cancellation token source for cancellation. Make sure to dispose after use (which is done here through the using expression).
using var tokenSource = new CancellationTokenSource();
// The cancellation token will be used to communicate cancellation to tasks
var token = tokenSource.Token;
Console.WriteLine("Main: Press any key to begin tasks...");
Console.ReadKey(true);
Console.WriteLine("Main: To terminate the example, press 'c' to cancel and exit...");
Console.WriteLine();
// Store references to the tasks so that we can wait on them and
// observe their status after cancellation.
var tasks = new ConcurrentBag<Task>();
// Pass the token to the user delegate so it can cancel during execution,
// and also to the task so it can cancel before execution starts.
var cancellableTask = Task.Run(() => {
DoSomeWork(token);
Console.WriteLine("Cancellable: Task {0} ran to completion", Task.CurrentId);
}, token);
Console.WriteLine("Main: Cancellable Task {0} created", cancellableTask.Id);
tasks.Add(cancellableTask);
var parentTask = Task.Run(() =>
{
for (int i = 0; i <= 7; i++)
{
// If cancellation was requested we don't need to start any more
// child tasks (that would immediately cancel) => break out of loop
if (token.IsCancellationRequested) break;
// For each child task, pass the same token
// to each user delegate and to Task.Run.
var childTask = Task.Run(() => {
DoSomeWork(token);
Console.WriteLine("Child: Task {0} ran to completion", Task.CurrentId);
}, token);
Console.WriteLine("Parent: Task {0} created", childTask.Id);
tasks.Add(childTask);
DoSomeWork(token, maxIterations: 1);
}
Console.WriteLine("Parent: Task {0} ran to completion", Task.CurrentId);
}, token);
Console.WriteLine("Main: Parent Task {0} created", parentTask.Id);
tasks.Add(parentTask);
// Request cancellation from the UI thread.
char ch = Console.ReadKey().KeyChar;
if (ch == 'c' || ch == 'C')
{
tokenSource.Cancel();
Console.WriteLine("\nMain: Task cancellation requested.");
// Optional: Observe the change in the Status property on the task.
// It is not necessary to wait on tasks that have canceled. However,
// if you do wait, you must enclose the call in a try-catch block to
// catch the OperationCanceledExceptions that are thrown. If you do
// not wait, no exception is thrown if the token that was passed to the
// Task.Run method is the same token that requested the cancellation.
}
try
{
// Wait for all tasks before disposing the cancellation token source
await Task.WhenAll(tasks);
}
catch (OperationCanceledException)
{
Console.WriteLine($"\nMain: {nameof(OperationCanceledException)} thrown\n");
}
// Display status of all tasks.
foreach (var task in tasks)
{
Console.WriteLine("Main: Task {0} status is now {1}", task.Id, task.Status);
}
}
static void DoSomeWork(CancellationToken ct, int maxIterations = 10)
{
// Was cancellation already requested?
if (ct.IsCancellationRequested)
{
Console.WriteLine("Task {0} was cancelled before it got started.", Task.CurrentId);
ct.ThrowIfCancellationRequested();
}
// NOTE!!! A "TaskCanceledException was unhandled
// by user code" error will be raised here if "Just My Code"
// is enabled on your computer. On Express editions JMC is
// enabled and cannot be disabled. The exception is benign.
// Just press F5 to continue executing your code.
for (int i = 0; i <= maxIterations; i++)
{
// Do a bit of work. Not too much.
var sw = new SpinWait();
for (int j = 0; j <= 100; j++)
sw.SpinOnce();
if (ct.IsCancellationRequested)
{
Console.WriteLine("Task {0} work cancelled", Task.CurrentId);
ct.ThrowIfCancellationRequested();
}
}
}
}
// The example displays output like the following:
// Main: Press any key to begin tasks...
// Main: To terminate the example, press 'c' to cancel and exit...
//
// Main: Cancellable Task 13 created
// Main: Parent Task 14 created
// Parent: Task 15 created
// Parent: Task 16 created
// Parent: Task 17 created
// Parent: Task 18 created
// Parent: Task 19 created
// Parent: Task 20 created
// Cancellable: Task 13 ran to completion
// Child: Task 15 ran to completion
// Parent: Task 21 created
// Child: Task 16 ran to completion
// Parent: Task 22 created
// Child: Task 17 ran to completion
// c
// Main: Task cancellation requested.
// Task 20 work cancelled
// Task 21 work cancelled
// Task 22 work cancelled
// Task 18 work cancelled
// Task 14 work cancelled
// Task 19 work cancelled
//
// Main: OperationCanceledException thrown
//
// Main: Task 22 status is now Canceled
// Main: Task 21 status is now Canceled
// Main: Task 20 status is now Canceled
// Main: Task 19 status is now Canceled
// Main: Task 18 status is now Canceled
// Main: Task 17 status is now RanToCompletion
// Main: Task 16 status is now RanToCompletion
// Main: Task 15 status is now RanToCompletion
// Main: Task 14 status is now Canceled
// Main: Task 13 status is now RanToCompletion
Imports System.Collections.Concurrent
Imports System.Threading
Imports System.Threading.Tasks
Module Example
Sub Main()
Dim tokenSource As New CancellationTokenSource()
Dim token As CancellationToken = tokenSource.Token
' Store references to the tasks so that we can wait on them and
' observe their status after cancellation.
Dim t As Task
Dim tasks As New ConcurrentBag(Of Task)()
Console.WriteLine("Press any key to begin tasks...")
Console.ReadKey(True)
Console.WriteLine("To terminate the example, press 'c' to cancel and exit...")
Console.WriteLine()
' Request cancellation of a single task when the token source is canceled.
' Pass the token to the user delegate, and also to the task so it can
' handle the exception correctly.
t = Task.Factory.StartNew(Sub() DoSomeWork(token), token)
Console.WriteLine("Task {0} executing", t.Id)
tasks.Add(t)
' Request cancellation of a task and its children. Note the token is passed
' to (1) the user delegate and (2) as the second argument to StartNew, so
' that the task instance can correctly handle the OperationCanceledException.
t = Task.Factory.StartNew(Sub()
' Create some cancelable child tasks.
Dim tc As Task
For i As Integer = 3 To 10
' For each child task, pass the same token
' to each user delegate and to StartNew.
tc = Task.Factory.StartNew(Sub(iteration) DoSomeWork(token), i, token)
Console.WriteLine("Task {0} executing", tc.Id)
tasks.Add(tc)
' Pass the same token again to do work on the parent task.
' All will be signaled by the call to tokenSource.Cancel below.
DoSomeWork(token)
Next
End Sub,
token)
Console.WriteLine("Task {0} executing", t.Id)
tasks.Add(t)
' Request cancellation from the UI thread.
Dim ch As Char = Console.ReadKey().KeyChar
If ch = "c"c Or ch = "C"c Then
tokenSource.Cancel()
Console.WriteLine(vbCrLf + "Task cancellation requested.")
' Optional: Observe the change in the Status property on the task.
' It is not necessary to wait on tasks that have canceled. However,
' if you do wait, you must enclose the call in a try-catch block to
' catch the OperationCanceledExceptions that are thrown. If you do
' not wait, no exception is thrown if the token that was passed to the
' StartNew method is the same token that requested the cancellation.
End If
Try
Task.WaitAll(tasks.ToArray())
Catch e As AggregateException
Console.WriteLine()
Console.WriteLine("AggregateException thrown with the following inner exceptions:")
' Display information about each exception.
For Each v In e.InnerExceptions
If TypeOf v Is OperationCanceledException Then
Console.WriteLine(" The operation was canceled.")
Else
Console.WriteLine(" Exception: {0}", v.GetType().Name)
End If
Next
Console.WriteLine()
Finally
tokenSource.Dispose()
End Try
' Display status of all tasks.
For Each t In tasks
Console.WriteLine("Task {0} status is now {1}", t.Id, t.Status)
Next
End Sub
Sub DoSomeWork(ByVal ct As CancellationToken)
' Was cancellation already requested?
If ct.IsCancellationRequested = True Then
Console.WriteLine("Task {0} was cancelled before it got started.",
Task.CurrentId)
ct.ThrowIfCancellationRequested()
End If
Dim maxIterations As Integer = 100
' NOTE!!! A "TaskCanceledException was unhandled
' by user code" error will be raised here if "Just My Code"
' is enabled on your computer. On Express editions JMC is
' enabled and cannot be disabled. The exception is benign.
' Just press F5 to continue executing your code.
For i As Integer = 0 To maxIterations
' Do a bit of work. Not too much.
Dim sw As New SpinWait()
For j As Integer = 0 To 100
sw.SpinOnce()
Next
If ct.IsCancellationRequested Then
Console.WriteLine("Task {0} cancelled", Task.CurrentId)
ct.ThrowIfCancellationRequested()
End If
Next
End Sub
End Module
' The example displays output like the following:
' Press any key to begin tasks...
' To terminate the example, press 'c' to cancel and exit...
'
' Task 1 executing
' Task 2 executing
' Task 3 executing
' Task 4 executing
' Task 5 executing
' Task 6 executing
' Task 7 executing
' Task 8 executing
' c
' Task cancellation requested.
' Task 2 cancelled
' Task 7 cancelled
'
' AggregateException thrown with the following inner exceptions:
' TaskCanceledException: Task 2
' TaskCanceledException: Task 8
' TaskCanceledException: Task 7
'
' Task 2 status is now Canceled
' Task 1 status is now RanToCompletion
' Task 8 status is now Canceled
' Task 7 status is now Canceled
' Task 6 status is now RanToCompletion
' Task 5 status is now RanToCompletion
' Task 4 status is now RanToCompletion
' Task 3 status is now RanToCompletion
Klassen System.Threading.Tasks.Task är helt integrerad med den annulleringsmodell som baseras på typerna System.Threading.CancellationTokenSource och System.Threading.CancellationToken . Mer information finns i Annullering i Hanterade trådar och Aktivitetsavbokning.