C# example using a CancellationTokenSource to signal to a CancellationToken that it should be cancelled.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
/// <summary>
/// The following example uses a random number generator to emulate a data
/// collection application that reads 10 integral values from eleven different
/// instruments. A value of zero indicates that the measurement has failed
/// for one instrument, in which case the operation should be cancelled
/// and no overall mean should be computed.
///
/// To handle the possible cancellation of the operation, the example
/// instantiates a CancellationTokenSource object that generates a
/// cancellation token which is passed to a TaskFactory object.
/// The TaskFactory object in turn passes the cancellation token to
/// each of the tasks responsible for collecting readings for a particular
/// instrument. The TaskFactory.ContinueWhenAll<TAntecedentResult,TResult>(Task<TAntecedentResult>[], Func<Task<TAntecedentResult>[],TResult>, CancellationToken)
/// method is called to ensure that the mean is computed only after all readings have been gathered successfully.
/// If a task has not because it has been cancelled, the call to the
/// TaskFactory.ContinueWhenAll method throws an exception.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netframework-4.8#examples</remarks>
public static void Main()
{
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Random rnd = new Random();
Object lockObj = new Object();
List<Task<int[]>> tasks = new List<Task<int[]>>();
TaskFactory factory = new TaskFactory(token);
for (int taskCtr = 0; taskCtr <= 10; taskCtr++)
{
int iteration = taskCtr + 1;
tasks.Add(factory.StartNew( () =>
{
int value;
int[] values = new int[10];
for (int ctr = 1; ctr <= 10; ctr++)
{
lock (lockObj)
{
value = rnd.Next(0, 101);
}
if (value == 0)
{
source.Cancel();
Console.WriteLine("Cancelling at task {0}", iteration);
break;
}
values[ctr - 1] = value;
}
return values;
}, token));
}
try
{
Task<double> fTask = factory.ContinueWhenAll(tasks.ToArray(), (results) =>
{
Console.WriteLine("Calculating overall mean...");
long sum = 0;
int n = 0;
foreach (var t in results)
{
foreach (var r in t.Result)
{
sum += r;
n++;
}
}
return sum / (double) n;
} , token);
Console.WriteLine("The mean is {0}.", fTask.Result);
}
catch (AggregateException ae)
{
foreach (Exception e in ae.InnerExceptions)
{
if (e is TaskCanceledException)
{
Console.WriteLine("Unable to compute mean: {0}", ((TaskCanceledException) e).Message);
}
else
{
Console.WriteLine("Exception: " + e.GetType().Name);
}
}
}
finally
{
source.Dispose();
}
}
}
// Repeated execution of the example produces output like the following:
// Cancelling at task 5
// Unable to compute mean: A task was canceled.
//
// Cancelling at task 10
// Unable to compute mean: A task was canceled.
//
// Calculating overall mean...
// The mean is 5.29545454545455.
//
// Cancelling at task 4
// Unable to compute mean: A task was canceled.
//
// Cancelling at task 5
// Unable to compute mean: A task was canceled.
//
// Cancelling at task 6
// Unable to compute mean: A task was canceled.
//
// Calculating overall mean...
// The mean is 4.97363636363636.
//
// Cancelling at task 4
// Unable to compute mean: A task was canceled.
//
// Cancelling at task 5
// Unable to compute mean: A task was canceled.
//
// Cancelling at task 4
// Unable to compute mean: A task was canceled.
//
// Calculating overall mean...
// The mean is 4.86545454545455.