In TPL, task cancellation is cooperative, so you need to define some means of indicating to your other tasks that they should stop executing. The most common way to do this is through CancellationTokenSource
, whose token can be checked for cancellation within your RunFuncX
methods.
static void Main()
{
InputDataType data = getMyData();
OutputDataType x = Foo(data).Result;
}
static async Task<OutputDataType> Foo(InputDataType data)
{
// Spawn your tasks, passing the cancellation token.
var cts = new CancellationTokenSource();
var task1 = Task.Factory.StartNew(() => RunFunc1(data, cts.Token));
var task2 = Task.Factory.StartNew(() => RunFunc2(data, cts.Token));
var task3 = Task.Factory.StartNew(() => RunFunc3(data, cts.Token));
var tasks = new [] { task1, task2, task3 };
// Loop while tasks are running.
while (tasks.Any())
{
// Wait for any task to complete.
var completedTask = await Task.WhenAny(tasks);
// If its result is good, indicate cancellation to the other tasks,
// and return the result.
if (IsResultGood(completedTask.Result))
{
cts.Cancel();
return completedTask.Result;
}
// Otherwise, remove the completed task from the array,
// and proceed to the next iteration.
tasks = tasks.Where(t => t != completedTask).ToArray();
}
// No good results.
return null;
}
Per Spo1ler's comment, I've updated your Foo
method to an asynchronous implementation. This assumes you're using C# 5.0. When consuming the method, use await
to get its result. If you're really running as a console application, your topmost call would need to block, so you can just get the task's Result
.